digital-tools 2.1.3 → 2.4.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +19 -0
- package/README.md +2 -0
- package/dist/client.d.ts +109 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +69 -0
- package/dist/client.js.map +1 -0
- package/dist/define.d.ts +2 -2
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +21 -11
- package/dist/define.js.map +1 -1
- package/dist/function-ref.d.ts +229 -0
- package/dist/function-ref.d.ts.map +1 -0
- package/dist/function-ref.js +28 -0
- package/dist/function-ref.js.map +1 -0
- package/dist/function-sugar.d.ts +57 -0
- package/dist/function-sugar.d.ts.map +1 -0
- package/dist/function-sugar.js +79 -0
- package/dist/function-sugar.js.map +1 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -4
- package/dist/index.js.map +1 -1
- package/dist/providers/analytics/mixpanel.d.ts.map +1 -1
- package/dist/providers/analytics/mixpanel.js +21 -18
- package/dist/providers/analytics/mixpanel.js.map +1 -1
- package/dist/providers/calendar/cal-com.d.ts.map +1 -1
- package/dist/providers/calendar/cal-com.js +10 -10
- package/dist/providers/calendar/cal-com.js.map +1 -1
- package/dist/providers/calendar/google-calendar.d.ts.map +1 -1
- package/dist/providers/calendar/google-calendar.js +4 -4
- package/dist/providers/calendar/google-calendar.js.map +1 -1
- package/dist/providers/crm/hubspot.d.ts.map +1 -1
- package/dist/providers/crm/hubspot.js +107 -85
- package/dist/providers/crm/hubspot.js.map +1 -1
- package/dist/providers/development/github.d.ts.map +1 -1
- package/dist/providers/development/github.js +40 -43
- package/dist/providers/development/github.js.map +1 -1
- package/dist/providers/ecommerce/shopify.d.ts.map +1 -1
- package/dist/providers/ecommerce/shopify.js +79 -62
- package/dist/providers/ecommerce/shopify.js.map +1 -1
- package/dist/providers/email/resend.d.ts.map +1 -1
- package/dist/providers/email/resend.js +20 -16
- package/dist/providers/email/resend.js.map +1 -1
- package/dist/providers/email/sendgrid.d.ts.map +1 -1
- package/dist/providers/email/sendgrid.js +12 -9
- package/dist/providers/email/sendgrid.js.map +1 -1
- package/dist/providers/finance/stripe.d.ts.map +1 -1
- package/dist/providers/finance/stripe.js +44 -42
- package/dist/providers/finance/stripe.js.map +1 -1
- package/dist/providers/forms/typeform.d.ts.map +1 -1
- package/dist/providers/forms/typeform.js +68 -58
- package/dist/providers/forms/typeform.js.map +1 -1
- package/dist/providers/knowledge/notion.d.ts.map +1 -1
- package/dist/providers/knowledge/notion.js +75 -41
- package/dist/providers/knowledge/notion.js.map +1 -1
- package/dist/providers/marketing/mailchimp.d.ts.map +1 -1
- package/dist/providers/marketing/mailchimp.js +74 -61
- package/dist/providers/marketing/mailchimp.js.map +1 -1
- package/dist/providers/media/cloudinary.d.ts.map +1 -1
- package/dist/providers/media/cloudinary.js +30 -28
- package/dist/providers/media/cloudinary.js.map +1 -1
- package/dist/providers/messaging/slack.d.ts.map +1 -1
- package/dist/providers/messaging/slack.js +75 -58
- package/dist/providers/messaging/slack.js.map +1 -1
- package/dist/providers/messaging/twilio-sms.d.ts.map +1 -1
- package/dist/providers/messaging/twilio-sms.js +33 -15
- package/dist/providers/messaging/twilio-sms.js.map +1 -1
- package/dist/providers/project-management/linear.d.ts.map +1 -1
- package/dist/providers/project-management/linear.js +31 -27
- package/dist/providers/project-management/linear.js.map +1 -1
- package/dist/providers/spreadsheet/google-sheets.d.ts.map +1 -1
- package/dist/providers/spreadsheet/google-sheets.js +21 -18
- package/dist/providers/spreadsheet/google-sheets.js.map +1 -1
- package/dist/providers/spreadsheet/xlsx.d.ts.map +1 -1
- package/dist/providers/spreadsheet/xlsx.js +4 -4
- package/dist/providers/spreadsheet/xlsx.js.map +1 -1
- package/dist/providers/storage/index.js +1 -0
- package/dist/providers/storage/index.js.map +1 -1
- package/dist/providers/storage/s3.d.ts.map +1 -1
- package/dist/providers/storage/s3.js +36 -27
- package/dist/providers/storage/s3.js.map +1 -1
- package/dist/providers/support/zendesk.d.ts.map +1 -1
- package/dist/providers/support/zendesk.js +24 -25
- package/dist/providers/support/zendesk.js.map +1 -1
- package/dist/providers/tasks/todoist.d.ts.map +1 -1
- package/dist/providers/tasks/todoist.js +18 -18
- package/dist/providers/tasks/todoist.js.map +1 -1
- package/dist/providers/video-conferencing/google-meet.d.ts.map +1 -1
- package/dist/providers/video-conferencing/google-meet.js +11 -11
- package/dist/providers/video-conferencing/google-meet.js.map +1 -1
- package/dist/providers/video-conferencing/jitsi.js +14 -14
- package/dist/providers/video-conferencing/jitsi.js.map +1 -1
- package/dist/providers/video-conferencing/teams.d.ts.map +1 -1
- package/dist/providers/video-conferencing/teams.js +9 -7
- package/dist/providers/video-conferencing/teams.js.map +1 -1
- package/dist/providers/video-conferencing/zoom.d.ts.map +1 -1
- package/dist/providers/video-conferencing/zoom.js +26 -24
- package/dist/providers/video-conferencing/zoom.js.map +1 -1
- package/dist/tools/data.d.ts.map +1 -1
- package/dist/tools/data.js +5 -12
- package/dist/tools/data.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/system.d.ts +289 -0
- package/dist/tools/system.d.ts.map +1 -0
- package/dist/tools/system.js +752 -0
- package/dist/tools/system.js.map +1 -0
- package/dist/tools/web.d.ts.map +1 -1
- package/dist/tools/web.js +22 -10
- package/dist/tools/web.js.map +1 -1
- package/dist/track-record.d.ts +101 -0
- package/dist/track-record.d.ts.map +1 -0
- package/dist/track-record.js +17 -0
- package/dist/track-record.js.map +1 -0
- package/dist/types.d.ts +210 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/verb-registration.d.ts +122 -0
- package/dist/verb-registration.d.ts.map +1 -0
- package/dist/verb-registration.js +176 -0
- package/dist/verb-registration.js.map +1 -0
- package/dist/worker.d.ts +93 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +315 -0
- package/dist/worker.js.map +1 -0
- package/dist/wrap.d.ts +89 -0
- package/dist/wrap.d.ts.map +1 -0
- package/dist/wrap.js +225 -0
- package/dist/wrap.js.map +1 -0
- package/package.json +31 -14
- package/src/client.ts +136 -0
- package/src/define.ts +30 -24
- package/src/function-ref.ts +264 -0
- package/src/function-sugar.ts +134 -0
- package/src/index.ts +132 -10
- package/src/providers/analytics/mixpanel.ts +19 -18
- package/src/providers/calendar/cal-com.ts +29 -18
- package/src/providers/calendar/google-calendar.ts +20 -14
- package/src/providers/crm/hubspot.ts +225 -99
- package/src/providers/development/github.ts +206 -135
- package/src/providers/ecommerce/shopify.ts +250 -89
- package/src/providers/email/resend.ts +101 -28
- package/src/providers/email/sendgrid.ts +12 -9
- package/src/providers/finance/stripe.ts +128 -49
- package/src/providers/forms/typeform.ts +74 -58
- package/src/providers/knowledge/notion.ts +340 -88
- package/src/providers/marketing/mailchimp.ts +86 -70
- package/src/providers/media/cloudinary.ts +99 -41
- package/src/providers/messaging/slack.ts +283 -85
- package/src/providers/messaging/twilio-sms.ts +35 -15
- package/src/providers/project-management/linear.ts +143 -55
- package/src/providers/spreadsheet/google-sheets.ts +222 -56
- package/src/providers/spreadsheet/xlsx.ts +47 -16
- package/src/providers/storage/s3.ts +119 -47
- package/src/providers/support/zendesk.ts +196 -46
- package/src/providers/tasks/todoist.ts +20 -26
- package/src/providers/video-conferencing/google-meet.ts +17 -20
- package/src/providers/video-conferencing/jitsi.ts +14 -14
- package/src/providers/video-conferencing/teams.ts +14 -13
- package/src/providers/video-conferencing/zoom.ts +54 -49
- package/src/tools/data.ts +6 -16
- package/src/tools/index.ts +1 -0
- package/src/tools/system.ts +887 -0
- package/src/tools/web.ts +22 -10
- package/src/track-record.ts +106 -0
- package/src/types.ts +241 -13
- package/src/verb-registration.ts +197 -0
- package/src/worker.ts +370 -0
- package/src/wrap.ts +260 -0
- package/test/client.test.ts +146 -0
- package/test/communication-tools-extended.test.ts +734 -0
- package/test/data-tools-extended.test.ts +743 -0
- package/test/define-extended.test.ts +819 -0
- package/test/define.test.ts +150 -41
- package/test/entities.test.ts +623 -0
- package/test/extended-entities.test.ts +1228 -0
- package/test/provider-implementations.test.ts +725 -0
- package/test/provider-registry-extended.test.ts +583 -0
- package/test/providers/google-sheets.test.ts +851 -0
- package/test/providers/helpers.ts +554 -0
- package/test/providers/hubspot.test.ts +576 -0
- package/test/providers/slack.test.ts +932 -0
- package/test/providers/stripe.test.ts +701 -0
- package/test/providers.test.ts +578 -0
- package/test/system-tools-extended.test.ts +632 -0
- package/test/system.test.ts +673 -0
- package/test/tools.test.ts +15 -11
- package/test/types.test.ts +402 -0
- package/test/verb-registration.test.ts +395 -0
- package/test/web-tools.test.ts +553 -0
- package/test/worker-extended.test.ts +699 -0
- package/test/worker.test.ts +576 -0
- package/test/wrap.test.ts +366 -0
- package/tsconfig.json +3 -13
- package/vitest.config.ts +37 -0
- package/wrangler.jsonc +9 -0
- package/LICENSE +0 -21
- package/dist/providers/voice/vapi.d.ts +0 -27
- package/dist/providers/voice/vapi.d.ts.map +0 -1
- package/dist/providers/voice/vapi.js +0 -440
- package/dist/providers/voice/vapi.js.map +0 -1
- package/src/define.js +0 -259
- package/src/entities/advertising.js +0 -999
- package/src/entities/ai.js +0 -756
- package/src/entities/analytics.js +0 -1588
- package/src/entities/automation.js +0 -601
- package/src/entities/communication.js +0 -1150
- package/src/entities/crm.js +0 -1386
- package/src/entities/design.js +0 -546
- package/src/entities/development.js +0 -2212
- package/src/entities/document.js +0 -874
- package/src/entities/ecommerce.js +0 -1429
- package/src/entities/experiment.js +0 -1039
- package/src/entities/finance.js +0 -3478
- package/src/entities/forms.js +0 -1892
- package/src/entities/hr.js +0 -661
- package/src/entities/identity.js +0 -997
- package/src/entities/index.js +0 -282
- package/src/entities/infrastructure.js +0 -1153
- package/src/entities/knowledge.js +0 -1438
- package/src/entities/marketing.js +0 -1610
- package/src/entities/media.js +0 -1634
- package/src/entities/notification.js +0 -1199
- package/src/entities/presentation.js +0 -1274
- package/src/entities/productivity.js +0 -1317
- package/src/entities/project-management.js +0 -1136
- package/src/entities/recruiting.js +0 -736
- package/src/entities/shipping.js +0 -509
- package/src/entities/signature.js +0 -1102
- package/src/entities/site.js +0 -222
- package/src/entities/spreadsheet.js +0 -1341
- package/src/entities/storage.js +0 -1198
- package/src/entities/support.js +0 -1166
- package/src/entities/video-conferencing.js +0 -1750
- package/src/entities/video.js +0 -950
- package/src/entities.js +0 -1663
- package/src/index.js +0 -74
- package/src/providers/analytics/index.js +0 -17
- package/src/providers/analytics/mixpanel.js +0 -255
- package/src/providers/calendar/cal-com.js +0 -303
- package/src/providers/calendar/google-calendar.js +0 -335
- package/src/providers/calendar/index.js +0 -20
- package/src/providers/crm/hubspot.js +0 -566
- package/src/providers/crm/index.js +0 -17
- package/src/providers/development/github.js +0 -472
- package/src/providers/development/index.js +0 -17
- package/src/providers/ecommerce/index.js +0 -17
- package/src/providers/ecommerce/shopify.js +0 -378
- package/src/providers/email/index.js +0 -20
- package/src/providers/email/resend.js +0 -258
- package/src/providers/email/sendgrid.js +0 -161
- package/src/providers/finance/index.js +0 -17
- package/src/providers/finance/stripe.js +0 -549
- package/src/providers/forms/index.js +0 -17
- package/src/providers/forms/typeform.js +0 -500
- package/src/providers/index.js +0 -123
- package/src/providers/knowledge/index.js +0 -17
- package/src/providers/knowledge/notion.js +0 -389
- package/src/providers/marketing/index.js +0 -17
- package/src/providers/marketing/mailchimp.js +0 -443
- package/src/providers/media/cloudinary.js +0 -318
- package/src/providers/media/index.js +0 -17
- package/src/providers/messaging/index.js +0 -20
- package/src/providers/messaging/slack.js +0 -393
- package/src/providers/messaging/twilio-sms.js +0 -249
- package/src/providers/project-management/index.js +0 -17
- package/src/providers/project-management/linear.js +0 -575
- package/src/providers/registry.js +0 -86
- package/src/providers/spreadsheet/google-sheets.js +0 -375
- package/src/providers/spreadsheet/index.js +0 -20
- package/src/providers/spreadsheet/xlsx.js +0 -423
- package/src/providers/storage/index.js +0 -24
- package/src/providers/storage/s3.js +0 -419
- package/src/providers/support/index.js +0 -17
- package/src/providers/support/zendesk.js +0 -373
- package/src/providers/tasks/index.js +0 -17
- package/src/providers/tasks/todoist.js +0 -286
- package/src/providers/types.js +0 -9
- package/src/providers/video-conferencing/google-meet.js +0 -286
- package/src/providers/video-conferencing/index.js +0 -31
- package/src/providers/video-conferencing/jitsi.js +0 -254
- package/src/providers/video-conferencing/teams.js +0 -270
- package/src/providers/video-conferencing/zoom.js +0 -332
- package/src/registry.js +0 -128
- package/src/tools/communication.js +0 -184
- package/src/tools/data.js +0 -205
- package/src/tools/index.js +0 -11
- package/src/tools/web.js +0 -137
- package/src/types.js +0 -10
- package/test/define.test.js +0 -306
- package/test/registry.test.js +0 -357
- package/test/tools.test.js +0 -363
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive Tests for Web Tools
|
|
3
|
+
*
|
|
4
|
+
* Tests fetchUrl, parseHtml, and readUrl tools with real network calls
|
|
5
|
+
* where available, and comprehensive edge case testing.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
9
|
+
import {
|
|
10
|
+
fetchUrl,
|
|
11
|
+
parseHtml,
|
|
12
|
+
readUrl,
|
|
13
|
+
webTools,
|
|
14
|
+
registry,
|
|
15
|
+
registerBuiltinTools,
|
|
16
|
+
} from '../src/index.js'
|
|
17
|
+
|
|
18
|
+
// Check if we have network access for integration tests
|
|
19
|
+
const hasNetwork = true // We'll test with real fetch
|
|
20
|
+
|
|
21
|
+
describe('Web Tools - fetchUrl', () => {
|
|
22
|
+
describe('metadata', () => {
|
|
23
|
+
it('has correct id', () => {
|
|
24
|
+
expect(fetchUrl.id).toBe('web.fetch')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('has correct name', () => {
|
|
28
|
+
expect(fetchUrl.name).toBe('Fetch URL')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('has correct category', () => {
|
|
32
|
+
expect(fetchUrl.category).toBe('web')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('has correct subcategory', () => {
|
|
36
|
+
expect(fetchUrl.subcategory).toBe('fetch')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('has description', () => {
|
|
40
|
+
expect(fetchUrl.description).toBe('Fetch content from a URL using HTTP')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('is for both audiences', () => {
|
|
44
|
+
expect(fetchUrl.audience).toBe('both')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('has http tag', () => {
|
|
48
|
+
expect(fetchUrl.tags).toContain('http')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('has network tag', () => {
|
|
52
|
+
expect(fetchUrl.tags).toContain('network')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('has api tag', () => {
|
|
56
|
+
expect(fetchUrl.tags).toContain('api')
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('parameters', () => {
|
|
61
|
+
it('has url parameter', () => {
|
|
62
|
+
const urlParam = fetchUrl.parameters.find((p) => p.name === 'url')
|
|
63
|
+
expect(urlParam).toBeDefined()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('url parameter is required', () => {
|
|
67
|
+
const urlParam = fetchUrl.parameters.find((p) => p.name === 'url')
|
|
68
|
+
expect(urlParam?.required).toBe(true)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('has method parameter', () => {
|
|
72
|
+
const methodParam = fetchUrl.parameters.find((p) => p.name === 'method')
|
|
73
|
+
expect(methodParam).toBeDefined()
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('method parameter is optional', () => {
|
|
77
|
+
const methodParam = fetchUrl.parameters.find((p) => p.name === 'method')
|
|
78
|
+
expect(methodParam?.required).toBe(false)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('has headers parameter', () => {
|
|
82
|
+
const headersParam = fetchUrl.parameters.find((p) => p.name === 'headers')
|
|
83
|
+
expect(headersParam).toBeDefined()
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('has body parameter', () => {
|
|
87
|
+
const bodyParam = fetchUrl.parameters.find((p) => p.name === 'body')
|
|
88
|
+
expect(bodyParam).toBeDefined()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('has 4 parameters total', () => {
|
|
92
|
+
expect(fetchUrl.parameters).toHaveLength(4)
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
describe('handler - real network tests', () => {
|
|
97
|
+
it('fetches a real URL with GET', async () => {
|
|
98
|
+
const result = await fetchUrl.handler({
|
|
99
|
+
url: 'https://httpbin.org/get',
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
expect(result.status).toBe(200)
|
|
103
|
+
expect(result.body).toBeDefined()
|
|
104
|
+
expect(typeof result.body).toBe('string')
|
|
105
|
+
expect(result.headers).toBeDefined()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('fetches with custom headers', async () => {
|
|
109
|
+
const result = await fetchUrl.handler({
|
|
110
|
+
url: 'https://httpbin.org/headers',
|
|
111
|
+
headers: {
|
|
112
|
+
'X-Custom-Header': 'test-value',
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
expect(result.status).toBe(200)
|
|
117
|
+
const body = JSON.parse(result.body)
|
|
118
|
+
expect(body.headers['X-Custom-Header']).toBe('test-value')
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('performs POST request', async () => {
|
|
122
|
+
const result = await fetchUrl.handler({
|
|
123
|
+
url: 'https://httpbin.org/post',
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: {
|
|
126
|
+
'Content-Type': 'application/json',
|
|
127
|
+
},
|
|
128
|
+
body: JSON.stringify({ test: 'data' }),
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
expect(result.status).toBe(200)
|
|
132
|
+
const body = JSON.parse(result.body)
|
|
133
|
+
expect(body.json).toEqual({ test: 'data' })
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('handles 404 response', async () => {
|
|
137
|
+
const result = await fetchUrl.handler({
|
|
138
|
+
url: 'https://httpbin.org/status/404',
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
expect(result.status).toBe(404)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('returns headers as object', async () => {
|
|
145
|
+
const result = await fetchUrl.handler({
|
|
146
|
+
url: 'https://httpbin.org/get',
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
expect(typeof result.headers).toBe('object')
|
|
150
|
+
expect(result.headers['content-type']).toBeDefined()
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
describe('Web Tools - parseHtml', () => {
|
|
156
|
+
describe('metadata', () => {
|
|
157
|
+
it('has correct id', () => {
|
|
158
|
+
expect(parseHtml.id).toBe('web.parse-html')
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('has correct name', () => {
|
|
162
|
+
expect(parseHtml.name).toBe('Parse HTML')
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('has correct category', () => {
|
|
166
|
+
expect(parseHtml.category).toBe('web')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('has correct subcategory', () => {
|
|
170
|
+
expect(parseHtml.subcategory).toBe('scrape')
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('has html tag', () => {
|
|
174
|
+
expect(parseHtml.tags).toContain('html')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('has parse tag', () => {
|
|
178
|
+
expect(parseHtml.tags).toContain('parse')
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('has extract tag', () => {
|
|
182
|
+
expect(parseHtml.tags).toContain('extract')
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
describe('parameters', () => {
|
|
187
|
+
it('has html parameter', () => {
|
|
188
|
+
const htmlParam = parseHtml.parameters.find((p) => p.name === 'html')
|
|
189
|
+
expect(htmlParam).toBeDefined()
|
|
190
|
+
expect(htmlParam?.required).toBe(true)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('has selector parameter', () => {
|
|
194
|
+
const selectorParam = parseHtml.parameters.find((p) => p.name === 'selector')
|
|
195
|
+
expect(selectorParam).toBeDefined()
|
|
196
|
+
expect(selectorParam?.required).toBe(false)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
describe('handler - text extraction', () => {
|
|
201
|
+
it('extracts text from simple HTML', async () => {
|
|
202
|
+
const result = await parseHtml.handler({
|
|
203
|
+
html: '<p>Hello World</p>',
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
expect(result.text).toBe('Hello World')
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('extracts text from nested elements', async () => {
|
|
210
|
+
const result = await parseHtml.handler({
|
|
211
|
+
html: '<div><p>First</p><span>Second</span></div>',
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
expect(result.text).toContain('First')
|
|
215
|
+
expect(result.text).toContain('Second')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('handles multiple whitespace', async () => {
|
|
219
|
+
const result = await parseHtml.handler({
|
|
220
|
+
html: '<p>Hello World</p>',
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
expect(result.text).toBe('Hello World')
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('handles newlines in HTML', async () => {
|
|
227
|
+
const result = await parseHtml.handler({
|
|
228
|
+
html: '<p>Line 1</p>\n<p>Line 2</p>',
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
expect(result.text).toContain('Line 1')
|
|
232
|
+
expect(result.text).toContain('Line 2')
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
it('strips all HTML tags', async () => {
|
|
236
|
+
const result = await parseHtml.handler({
|
|
237
|
+
html: '<b>Bold</b> and <i>italic</i>',
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
expect(result.text).toBe('Bold and italic')
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
describe('handler - link extraction', () => {
|
|
245
|
+
it('extracts links from href attributes', async () => {
|
|
246
|
+
const result = await parseHtml.handler({
|
|
247
|
+
html: '<a href="https://example.com">Link</a>',
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
expect(result.links).toContain('https://example.com')
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('extracts multiple links', async () => {
|
|
254
|
+
const result = await parseHtml.handler({
|
|
255
|
+
html: '<a href="https://a.com">A</a><a href="https://b.com">B</a>',
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
expect(result.links).toHaveLength(2)
|
|
259
|
+
expect(result.links).toContain('https://a.com')
|
|
260
|
+
expect(result.links).toContain('https://b.com')
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it('extracts relative links', async () => {
|
|
264
|
+
const result = await parseHtml.handler({
|
|
265
|
+
html: '<a href="/path/to/page">Page</a>',
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
expect(result.links).toContain('/path/to/page')
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('returns empty array when no links', async () => {
|
|
272
|
+
const result = await parseHtml.handler({
|
|
273
|
+
html: '<p>No links here</p>',
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
expect(result.links).toEqual([])
|
|
277
|
+
})
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
describe('handler - image extraction', () => {
|
|
281
|
+
it('extracts jpg images', async () => {
|
|
282
|
+
const result = await parseHtml.handler({
|
|
283
|
+
html: '<img src="image.jpg" />',
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
expect(result.images).toContain('image.jpg')
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
it('extracts png images', async () => {
|
|
290
|
+
const result = await parseHtml.handler({
|
|
291
|
+
html: '<img src="photo.png" />',
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
expect(result.images).toContain('photo.png')
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('extracts gif images', async () => {
|
|
298
|
+
const result = await parseHtml.handler({
|
|
299
|
+
html: '<img src="animation.gif" />',
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
expect(result.images).toContain('animation.gif')
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('extracts webp images', async () => {
|
|
306
|
+
const result = await parseHtml.handler({
|
|
307
|
+
html: '<img src="modern.webp" />',
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
expect(result.images).toContain('modern.webp')
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
it('extracts svg images', async () => {
|
|
314
|
+
const result = await parseHtml.handler({
|
|
315
|
+
html: '<img src="icon.svg" />',
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
expect(result.images).toContain('icon.svg')
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
it('extracts jpeg images', async () => {
|
|
322
|
+
const result = await parseHtml.handler({
|
|
323
|
+
html: '<img src="picture.jpeg" />',
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
expect(result.images).toContain('picture.jpeg')
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
it('extracts multiple images', async () => {
|
|
330
|
+
const result = await parseHtml.handler({
|
|
331
|
+
html: '<img src="a.jpg" /><img src="b.png" />',
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
expect(result.images).toHaveLength(2)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('does not extract non-image src attributes', async () => {
|
|
338
|
+
const result = await parseHtml.handler({
|
|
339
|
+
html: '<script src="app.js"></script>',
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
expect(result.images).not.toContain('app.js')
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
it('returns empty array when no images', async () => {
|
|
346
|
+
const result = await parseHtml.handler({
|
|
347
|
+
html: '<p>No images here</p>',
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
expect(result.images).toEqual([])
|
|
351
|
+
})
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
describe('handler - complex HTML', () => {
|
|
355
|
+
it('handles complete HTML document', async () => {
|
|
356
|
+
const html = `
|
|
357
|
+
<!DOCTYPE html>
|
|
358
|
+
<html>
|
|
359
|
+
<head><title>Test Page</title></head>
|
|
360
|
+
<body>
|
|
361
|
+
<h1>Welcome</h1>
|
|
362
|
+
<p>This is content.</p>
|
|
363
|
+
<a href="https://example.com">Link</a>
|
|
364
|
+
<img src="photo.jpg" />
|
|
365
|
+
</body>
|
|
366
|
+
</html>
|
|
367
|
+
`
|
|
368
|
+
|
|
369
|
+
const result = await parseHtml.handler({ html })
|
|
370
|
+
|
|
371
|
+
expect(result.text).toContain('Welcome')
|
|
372
|
+
expect(result.text).toContain('This is content')
|
|
373
|
+
expect(result.links).toContain('https://example.com')
|
|
374
|
+
expect(result.images).toContain('photo.jpg')
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('handles empty HTML', async () => {
|
|
378
|
+
const result = await parseHtml.handler({ html: '' })
|
|
379
|
+
|
|
380
|
+
expect(result.text).toBe('')
|
|
381
|
+
expect(result.links).toEqual([])
|
|
382
|
+
expect(result.images).toEqual([])
|
|
383
|
+
})
|
|
384
|
+
})
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
describe('Web Tools - readUrl', () => {
|
|
388
|
+
describe('metadata', () => {
|
|
389
|
+
it('has correct id', () => {
|
|
390
|
+
expect(readUrl.id).toBe('web.read')
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('has correct name', () => {
|
|
394
|
+
expect(readUrl.name).toBe('Read URL')
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
it('has correct category', () => {
|
|
398
|
+
expect(readUrl.category).toBe('web')
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
it('has correct subcategory', () => {
|
|
402
|
+
expect(readUrl.subcategory).toBe('scrape')
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
it('is idempotent', () => {
|
|
406
|
+
expect(readUrl.idempotent).toBe(true)
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
it('has read tag', () => {
|
|
410
|
+
expect(readUrl.tags).toContain('read')
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
it('has scrape tag', () => {
|
|
414
|
+
expect(readUrl.tags).toContain('scrape')
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
it('has extract tag', () => {
|
|
418
|
+
expect(readUrl.tags).toContain('extract')
|
|
419
|
+
})
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
describe('parameters', () => {
|
|
423
|
+
it('has url parameter', () => {
|
|
424
|
+
const urlParam = readUrl.parameters.find((p) => p.name === 'url')
|
|
425
|
+
expect(urlParam).toBeDefined()
|
|
426
|
+
expect(urlParam?.required).toBe(true)
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
it('has only 1 parameter', () => {
|
|
430
|
+
expect(readUrl.parameters).toHaveLength(1)
|
|
431
|
+
})
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
describe('handler - real network tests', () => {
|
|
435
|
+
it('reads a real webpage', async () => {
|
|
436
|
+
const result = await readUrl.handler({
|
|
437
|
+
url: 'https://example.com',
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
expect(result.title).toBeDefined()
|
|
441
|
+
expect(result.text).toBeDefined()
|
|
442
|
+
expect(result.links).toBeDefined()
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
it('extracts title from page', async () => {
|
|
446
|
+
const result = await readUrl.handler({
|
|
447
|
+
url: 'https://example.com',
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
expect(typeof result.title).toBe('string')
|
|
451
|
+
expect(result.title.length).toBeGreaterThan(0)
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
it('extracts text from page body', async () => {
|
|
455
|
+
const result = await readUrl.handler({
|
|
456
|
+
url: 'https://example.com',
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
expect(typeof result.text).toBe('string')
|
|
460
|
+
expect(result.text.length).toBeGreaterThan(0)
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
it('extracts unique links', async () => {
|
|
464
|
+
const result = await readUrl.handler({
|
|
465
|
+
url: 'https://example.com',
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
expect(Array.isArray(result.links)).toBe(true)
|
|
469
|
+
// Check for uniqueness
|
|
470
|
+
const uniqueLinks = [...new Set(result.links)]
|
|
471
|
+
expect(uniqueLinks.length).toBe(result.links.length)
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
it('limits text to 10000 characters', async () => {
|
|
475
|
+
const result = await readUrl.handler({
|
|
476
|
+
url: 'https://example.com',
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
expect(result.text.length).toBeLessThanOrEqual(10000)
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
describe('Web Tools Array', () => {
|
|
485
|
+
it('contains fetchUrl', () => {
|
|
486
|
+
expect(webTools.map((t) => t.id)).toContain('web.fetch')
|
|
487
|
+
})
|
|
488
|
+
|
|
489
|
+
it('contains parseHtml', () => {
|
|
490
|
+
expect(webTools.map((t) => t.id)).toContain('web.parse-html')
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
it('contains readUrl', () => {
|
|
494
|
+
expect(webTools.map((t) => t.id)).toContain('web.read')
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
it('has exactly 3 tools', () => {
|
|
498
|
+
expect(webTools).toHaveLength(3)
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
it('all tools have web category', () => {
|
|
502
|
+
expect(webTools.every((t) => t.category === 'web')).toBe(true)
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
it('all tools have handlers', () => {
|
|
506
|
+
expect(webTools.every((t) => typeof t.handler === 'function')).toBe(true)
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
it('all tools have parameters', () => {
|
|
510
|
+
expect(webTools.every((t) => Array.isArray(t.parameters))).toBe(true)
|
|
511
|
+
})
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
describe('Web Tools Registry Integration', () => {
|
|
515
|
+
beforeEach(() => {
|
|
516
|
+
registry.clear()
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
it('can register web tools', () => {
|
|
520
|
+
for (const tool of webTools) {
|
|
521
|
+
registry.register(tool)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
expect(registry.has('web.fetch')).toBe(true)
|
|
525
|
+
expect(registry.has('web.parse-html')).toBe(true)
|
|
526
|
+
expect(registry.has('web.read')).toBe(true)
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
it('can query web tools by category', () => {
|
|
530
|
+
registerBuiltinTools()
|
|
531
|
+
|
|
532
|
+
const tools = registry.byCategory('web')
|
|
533
|
+
expect(tools.length).toBeGreaterThanOrEqual(3)
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
it('can find tools by subcategory', () => {
|
|
537
|
+
registerBuiltinTools()
|
|
538
|
+
|
|
539
|
+
const fetchTools = registry.query({ subcategory: 'fetch' })
|
|
540
|
+
expect(fetchTools.some((t) => t.id === 'web.fetch')).toBe(true)
|
|
541
|
+
|
|
542
|
+
const scrapeTools = registry.query({ subcategory: 'scrape' })
|
|
543
|
+
expect(scrapeTools.some((t) => t.id === 'web.parse-html')).toBe(true)
|
|
544
|
+
expect(scrapeTools.some((t) => t.id === 'web.read')).toBe(true)
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
it('can search for tools by text', () => {
|
|
548
|
+
registerBuiltinTools()
|
|
549
|
+
|
|
550
|
+
const results = registry.query({ search: 'fetch' })
|
|
551
|
+
expect(results.some((t) => t.id === 'web.fetch')).toBe(true)
|
|
552
|
+
})
|
|
553
|
+
})
|