@commandable/integration-data 0.0.1 → 0.0.4
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/dist/credentials-index.d.ts +4 -21
- package/dist/credentials-index.d.ts.map +1 -1
- package/dist/credentials-index.js +407 -215
- package/dist/credentials-index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +38 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +70 -16
- package/dist/loader.js.map +1 -1
- package/integrations/__tests__/liveHarness.ts +84 -0
- package/integrations/__tests__/usageParity.ts +54 -0
- package/integrations/airtable/__tests__/get_handlers.test.ts +18 -15
- package/integrations/airtable/__tests__/usage_parity.test.ts +3 -29
- package/integrations/airtable/__tests__/write_and_admin_handlers.test.ts +20 -17
- package/integrations/airtable/credentials.json +21 -16
- package/integrations/github/__tests__/get_handlers.test.ts +101 -108
- package/integrations/github/__tests__/usage_parity.test.ts +15 -27
- package/integrations/github/__tests__/write_handlers.test.ts +219 -306
- package/integrations/github/credentials.json +40 -15
- package/integrations/github/credentials_hint_classic_pat.md +8 -0
- package/integrations/github/credentials_hint_fine_grained_pat.md +9 -0
- package/integrations/github/manifest.json +2 -2
- package/integrations/google-calendar/__tests__/get_handlers.test.ts +21 -13
- package/integrations/google-calendar/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +24 -17
- package/integrations/google-calendar/credentials.json +50 -29
- package/integrations/google-calendar/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-calendar/credentials_hint_service_account.md +10 -0
- package/integrations/google-docs/__tests__/get_handlers.test.ts +87 -61
- package/integrations/google-docs/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-docs/__tests__/write_handlers.test.ts +248 -245
- package/integrations/google-docs/credentials.json +50 -29
- package/integrations/google-docs/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-docs/credentials_hint_service_account.md +10 -0
- package/integrations/google-drive/credentials.json +57 -0
- package/integrations/google-drive/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-drive/credentials_hint_service_account.md +10 -0
- package/integrations/google-drive/handlers/create_file.js +15 -0
- package/integrations/google-drive/handlers/create_folder.js +15 -0
- package/integrations/google-drive/handlers/delete_file.js +14 -0
- package/integrations/google-drive/handlers/get_file.js +7 -0
- package/integrations/google-drive/handlers/move_file.js +12 -0
- package/integrations/google-drive/manifest.json +42 -0
- package/integrations/google-drive/schemas/create_file.json +12 -0
- package/integrations/google-drive/schemas/create_folder.json +11 -0
- package/integrations/google-drive/schemas/delete_file.json +10 -0
- package/integrations/google-drive/schemas/get_file.json +10 -0
- package/integrations/google-drive/schemas/move_file.json +12 -0
- package/integrations/google-sheet/__tests__/get_handlers.test.ts +47 -55
- package/integrations/google-sheet/__tests__/usage_parity.test.ts +3 -29
- package/integrations/google-sheet/__tests__/write_handlers.test.ts +64 -63
- package/integrations/google-sheet/credentials.json +50 -29
- package/integrations/google-sheet/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-sheet/credentials_hint_service_account.md +10 -0
- package/integrations/google-slides/__tests__/get_handlers.test.ts +37 -36
- package/integrations/google-slides/__tests__/usage_parity.test.ts +3 -28
- package/integrations/google-slides/__tests__/write_handlers.test.ts +65 -58
- package/integrations/google-slides/credentials.json +50 -29
- package/integrations/google-slides/credentials_hint_oauth_token.md +8 -0
- package/integrations/google-slides/credentials_hint_service_account.md +10 -0
- package/integrations/notion/__tests__/get_handlers.test.ts +18 -15
- package/integrations/notion/__tests__/usage_parity.test.ts +3 -28
- package/integrations/notion/__tests__/write_and_admin_handlers.test.ts +56 -60
- package/integrations/notion/credentials.json +22 -17
- package/integrations/trello/__tests__/get_handlers.test.ts +58 -73
- package/integrations/trello/__tests__/usage_parity.test.ts +3 -28
- package/integrations/trello/__tests__/write_and_admin_handlers.test.ts +49 -67
- package/integrations/trello/credentials.json +26 -21
- package/integrations/trello/handlers/close_board.js +6 -0
- package/integrations/trello/handlers/create_board.js +11 -0
- package/integrations/trello/handlers/delete_board.js +13 -0
- package/integrations/trello/manifest.json +21 -0
- package/integrations/trello/schemas/close_board.json +10 -0
- package/integrations/trello/schemas/create_board.json +12 -0
- package/integrations/trello/schemas/delete_board.json +10 -0
- package/package.json +1 -1
|
@@ -2,11 +2,9 @@ import { beforeAll, describe, expect, it } from 'vitest'
|
|
|
2
2
|
import { IntegrationProxy } from '../../../../server/src/integrations/proxy.js'
|
|
3
3
|
import { loadIntegrationTools } from '../../../../server/src/integrations/dataLoader.js'
|
|
4
4
|
|
|
5
|
-
// LIVE Google Calendar read tests using
|
|
5
|
+
// LIVE Google Calendar read tests using credentials
|
|
6
6
|
// Required env vars:
|
|
7
|
-
// -
|
|
8
|
-
// - COMMANDABLE_MANAGED_OAUTH_SECRET_KEY
|
|
9
|
-
// - GCAL_TEST_CONNECTION_ID (managed OAuth connection for provider 'google-calendar')
|
|
7
|
+
// - Either GOOGLE_TOKEN, OR (GOOGLE_SERVICE_ACCOUNT_JSON + GOOGLE_IMPERSONATE_SUBJECT)
|
|
10
8
|
|
|
11
9
|
interface Ctx {
|
|
12
10
|
calendarId?: string
|
|
@@ -16,10 +14,9 @@ interface Ctx {
|
|
|
16
14
|
const env = process.env as Record<string, string>
|
|
17
15
|
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
18
16
|
const suite = hasEnv(
|
|
19
|
-
'
|
|
20
|
-
'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY',
|
|
21
|
-
'GCAL_TEST_CONNECTION_ID',
|
|
17
|
+
'GOOGLE_TOKEN',
|
|
22
18
|
)
|
|
19
|
+
|| hasEnv('GOOGLE_SERVICE_ACCOUNT_JSON', 'GOOGLE_IMPERSONATE_SUBJECT')
|
|
23
20
|
? describe
|
|
24
21
|
: describe.skip
|
|
25
22
|
|
|
@@ -28,13 +25,24 @@ suite('google-calendar read handlers (live)', () => {
|
|
|
28
25
|
let buildHandler: (name: string) => ((input: any) => Promise<any>)
|
|
29
26
|
|
|
30
27
|
beforeAll(async () => {
|
|
31
|
-
const
|
|
28
|
+
const credentialStore = {
|
|
29
|
+
getCredentials: async () => ({
|
|
30
|
+
token: env.GOOGLE_TOKEN || '',
|
|
31
|
+
serviceAccountJson: env.GOOGLE_SERVICE_ACCOUNT_JSON || '',
|
|
32
|
+
subject: env.GOOGLE_IMPERSONATE_SUBJECT || '',
|
|
33
|
+
}),
|
|
34
|
+
}
|
|
32
35
|
|
|
33
|
-
const proxy = new IntegrationProxy({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const proxy = new IntegrationProxy({ credentialStore })
|
|
37
|
+
const integrationNode = {
|
|
38
|
+
spaceId: 'ci',
|
|
39
|
+
id: 'node-gcal',
|
|
40
|
+
referenceId: 'node-gcal',
|
|
41
|
+
type: 'google-calendar',
|
|
42
|
+
label: 'Google Calendar',
|
|
43
|
+
connectionMethod: 'credentials',
|
|
44
|
+
credentialId: 'google-calendar-creds',
|
|
45
|
+
} as any
|
|
38
46
|
|
|
39
47
|
const tools = loadIntegrationTools('google-calendar')
|
|
40
48
|
expect(tools).toBeTruthy()
|
|
@@ -1,34 +1,9 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
1
|
import { describe, expect, it } from 'vitest'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
function escapeRegExp(str: string): string {
|
|
8
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
9
|
-
}
|
|
2
|
+
import { getMissingToolUsages } from '../../__tests__/usageParity.js'
|
|
10
3
|
|
|
11
4
|
describe('google-calendar static usage parity', () => {
|
|
12
|
-
it('every manifest tool is referenced in tests
|
|
13
|
-
const
|
|
14
|
-
const toolNames = (manifest.tools as any[]).map(t => t.name)
|
|
15
|
-
|
|
16
|
-
const testsDir = fileURLToPath(new URL('.', import.meta.url))
|
|
17
|
-
expect(existsSync(testsDir)).toBe(true)
|
|
18
|
-
const testFiles = readdirSync(testsDir)
|
|
19
|
-
.filter(f => /\.test\.(t|j)s$/.test(f) && !f.includes('usage_parity.test'))
|
|
20
|
-
.map(f => resolve(testsDir, f))
|
|
21
|
-
|
|
22
|
-
const fileContents = testFiles.map(f => readFileSync(f, 'utf8'))
|
|
23
|
-
|
|
24
|
-
const missing: string[] = []
|
|
25
|
-
for (const name of toolNames) {
|
|
26
|
-
const nameRe = new RegExp(`build(?:Read|Write|Admin|Handler)\\(\\s*['\"\`]${escapeRegExp(name)}['\"\`]\\s*\\)`, 'm')
|
|
27
|
-
const found = fileContents.some(src => nameRe.test(src))
|
|
28
|
-
if (!found)
|
|
29
|
-
missing.push(name)
|
|
30
|
-
}
|
|
31
|
-
|
|
5
|
+
it('every manifest tool is referenced in tests', () => {
|
|
6
|
+
const missing = getMissingToolUsages({ integrationName: 'google-calendar', importMetaUrl: import.meta.url })
|
|
32
7
|
expect(missing, `Missing handler usages in tests: ${missing.join(', ')}`).toEqual([])
|
|
33
8
|
})
|
|
34
9
|
})
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
-
import { IntegrationProxy } from '
|
|
3
|
-
import { loadIntegrationTools } from '
|
|
2
|
+
import { IntegrationProxy } from '../../../../server/src/integrations/proxy.js'
|
|
3
|
+
import { loadIntegrationTools } from '../../../../server/src/integrations/dataLoader.js'
|
|
4
4
|
|
|
5
|
-
// LIVE Google Calendar write/admin tests using
|
|
5
|
+
// LIVE Google Calendar write/admin tests using credentials
|
|
6
6
|
// Required env vars:
|
|
7
|
-
// -
|
|
8
|
-
// - COMMANDABLE_MANAGED_OAUTH_SECRET_KEY
|
|
9
|
-
// - GCAL_TEST_CONNECTION_ID (managed OAuth connection for provider 'google-calendar')
|
|
7
|
+
// - Either GOOGLE_TOKEN, OR (GOOGLE_SERVICE_ACCOUNT_JSON + GOOGLE_IMPERSONATE_SUBJECT)
|
|
10
8
|
// Optional:
|
|
11
9
|
// - GCAL_TEST_CALENDAR_ID (defaults to 'primary')
|
|
12
10
|
|
|
@@ -18,11 +16,7 @@ interface Ctx {
|
|
|
18
16
|
|
|
19
17
|
const env = process.env as Record<string, string>
|
|
20
18
|
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
21
|
-
const suite = hasEnv(
|
|
22
|
-
'COMMANDABLE_MANAGED_OAUTH_BASE_URL',
|
|
23
|
-
'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY',
|
|
24
|
-
'GCAL_TEST_CONNECTION_ID',
|
|
25
|
-
)
|
|
19
|
+
const suite = hasEnv('GOOGLE_TOKEN') || hasEnv('GOOGLE_SERVICE_ACCOUNT_JSON', 'GOOGLE_IMPERSONATE_SUBJECT')
|
|
26
20
|
? describe
|
|
27
21
|
: describe.skip
|
|
28
22
|
|
|
@@ -33,15 +27,28 @@ suite('google-calendar write & admin handlers (live)', () => {
|
|
|
33
27
|
let buildAdmin: (name: string) => ((input: any) => Promise<any>)
|
|
34
28
|
|
|
35
29
|
beforeAll(async () => {
|
|
36
|
-
const {
|
|
30
|
+
const { GCAL_TEST_CALENDAR_ID } = env
|
|
37
31
|
|
|
38
32
|
ctx.calendarId = GCAL_TEST_CALENDAR_ID || 'primary'
|
|
39
33
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
const credentialStore = {
|
|
35
|
+
getCredentials: async () => ({
|
|
36
|
+
token: env.GOOGLE_TOKEN || '',
|
|
37
|
+
serviceAccountJson: env.GOOGLE_SERVICE_ACCOUNT_JSON || '',
|
|
38
|
+
subject: env.GOOGLE_IMPERSONATE_SUBJECT || '',
|
|
39
|
+
}),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const proxy = new IntegrationProxy({ credentialStore })
|
|
43
|
+
const integrationNode = {
|
|
44
|
+
spaceId: 'ci',
|
|
45
|
+
id: 'node-gcal',
|
|
46
|
+
referenceId: 'node-gcal',
|
|
47
|
+
type: 'google-calendar',
|
|
48
|
+
label: 'Google Calendar',
|
|
49
|
+
connectionMethod: 'credentials',
|
|
50
|
+
credentialId: 'google-calendar-creds',
|
|
51
|
+
} as any
|
|
45
52
|
|
|
46
53
|
const tools = loadIntegrationTools('google-calendar')
|
|
47
54
|
expect(tools).toBeTruthy()
|
|
@@ -1,36 +1,57 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"type": "
|
|
7
|
-
"
|
|
8
|
-
|
|
2
|
+
"variants": {
|
|
3
|
+
"service_account": {
|
|
4
|
+
"label": "Service Account (recommended)",
|
|
5
|
+
"schema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"serviceAccountJson": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"title": "Service Account JSON",
|
|
11
|
+
"description": "Full service account key JSON (contents of the downloaded JSON file from Google Cloud)."
|
|
12
|
+
},
|
|
13
|
+
"subject": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"title": "Subject / impersonated user (optional)",
|
|
16
|
+
"description": "User email to impersonate via Google Workspace domain-wide delegation. Required for most Calendar operations."
|
|
17
|
+
},
|
|
18
|
+
"scopes": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"title": "OAuth scopes (optional)",
|
|
21
|
+
"description": "Optional override for OAuth scopes. Defaults to calendar.",
|
|
22
|
+
"items": { "type": "string" }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"required": ["serviceAccountJson"],
|
|
26
|
+
"additionalProperties": false
|
|
9
27
|
},
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
28
|
+
"injection": {
|
|
29
|
+
"headers": {
|
|
30
|
+
"Authorization": "Bearer {{token}}"
|
|
31
|
+
}
|
|
14
32
|
},
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
33
|
+
"preprocess": "google_service_account"
|
|
34
|
+
},
|
|
35
|
+
"oauth_token": {
|
|
36
|
+
"label": "OAuth Access Token (short-lived)",
|
|
37
|
+
"schema": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"token": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"title": "OAuth Access Token",
|
|
43
|
+
"description": "Short-lived Google OAuth access token with calendar scope."
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"required": ["token"],
|
|
47
|
+
"additionalProperties": false
|
|
19
48
|
},
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"items": { "type": "string" }
|
|
49
|
+
"injection": {
|
|
50
|
+
"headers": {
|
|
51
|
+
"Authorization": "Bearer {{token}}"
|
|
52
|
+
}
|
|
25
53
|
}
|
|
26
|
-
},
|
|
27
|
-
"required": [],
|
|
28
|
-
"additionalProperties": false
|
|
29
|
-
},
|
|
30
|
-
"injection": {
|
|
31
|
-
"headers": {
|
|
32
|
-
"Authorization": "Bearer {{token}}"
|
|
33
54
|
}
|
|
34
|
-
}
|
|
55
|
+
},
|
|
56
|
+
"default": "service_account"
|
|
35
57
|
}
|
|
36
|
-
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Obtain a short-lived Google OAuth access token:
|
|
2
|
+
|
|
3
|
+
1. Use the Google OAuth 2.0 Playground (`https://developers.google.com/oauthplayground/`) or your own OAuth flow
|
|
4
|
+
2. Select the scope: `https://www.googleapis.com/auth/calendar`
|
|
5
|
+
3. Exchange the authorization code for an access token
|
|
6
|
+
4. Paste the access token here
|
|
7
|
+
|
|
8
|
+
Note: OAuth access tokens are short-lived (typically 1 hour). For long-running use, prefer the Service Account variant.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Set up a Google Cloud Service Account:
|
|
2
|
+
|
|
3
|
+
1. Open the [Google Cloud Console](https://console.cloud.google.com/)
|
|
4
|
+
2. Enable the **Google Calendar API** for your project
|
|
5
|
+
3. Go to **IAM & Admin → Service Accounts** and create a new service account
|
|
6
|
+
4. Under **Keys**, click **Add Key → Create new key → JSON** and download the file
|
|
7
|
+
5. Paste the full contents of the JSON file here
|
|
8
|
+
|
|
9
|
+
For Google Workspace users: Calendar access typically requires domain-wide delegation.
|
|
10
|
+
Configure it in the Google Admin console, then set `subject` to the calendar owner's email.
|
|
@@ -1,72 +1,98 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import { loadIntegrationTools } from '../../../src/integrations/dataLoader.js'
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
2
|
+
import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv, safeCleanup } from '../../__tests__/liveHarness.js'
|
|
4
3
|
|
|
5
|
-
// LIVE Google Docs read tests
|
|
6
|
-
// Required env vars:
|
|
7
|
-
// -
|
|
8
|
-
// -
|
|
9
|
-
// - GDOCS_TEST_CONNECTION_ID (managed OAuth connection for provider 'google-docs')
|
|
10
|
-
// - GDOCS_TEST_DOCUMENT_ID (an accessible document ID)
|
|
4
|
+
// LIVE Google Docs read tests -- runs once per available credential variant.
|
|
5
|
+
// Required env vars (at least one):
|
|
6
|
+
// - GOOGLE_SERVICE_ACCOUNT_JSON (service_account variant)
|
|
7
|
+
// - GOOGLE_TOKEN (oauth_token variant)
|
|
11
8
|
|
|
12
|
-
const env = process.env as Record<string, string>
|
|
13
|
-
const hasEnv = (...keys: string[]) => keys.every(k => !!env[k] && env[k].trim().length > 0)
|
|
14
|
-
const suite = hasEnv(
|
|
15
|
-
'COMMANDABLE_MANAGED_OAUTH_BASE_URL',
|
|
16
|
-
'COMMANDABLE_MANAGED_OAUTH_SECRET_KEY',
|
|
17
|
-
'GDOCS_TEST_CONNECTION_ID',
|
|
18
|
-
)
|
|
19
|
-
? describe
|
|
20
|
-
: describe.skip
|
|
9
|
+
const env = process.env as Record<string, string | undefined>
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
interface VariantConfig {
|
|
12
|
+
key: string
|
|
13
|
+
credentials: () => Record<string, string>
|
|
14
|
+
}
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
const variants: VariantConfig[] = [
|
|
17
|
+
{
|
|
18
|
+
key: 'service_account',
|
|
19
|
+
credentials: () => ({ serviceAccountJson: env.GOOGLE_SERVICE_ACCOUNT_JSON || '' }),
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: 'oauth_token',
|
|
23
|
+
credentials: () => ({ token: env.GOOGLE_TOKEN || '' }),
|
|
24
|
+
},
|
|
25
|
+
].filter(v => Object.values(v.credentials()).some(val => val.trim().length > 0))
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const suiteOrSkip = variants.length > 0 ? describe : describe.skip
|
|
28
|
+
|
|
29
|
+
suiteOrSkip('google-docs read handlers (live)', () => {
|
|
30
|
+
for (const variant of variants) {
|
|
31
|
+
describe(`variant: ${variant.key}`, () => {
|
|
32
|
+
let docs: ReturnType<typeof createToolbox>
|
|
33
|
+
let drive: ReturnType<typeof createToolbox>
|
|
34
|
+
let folderId: string | undefined
|
|
35
|
+
let documentId: string | undefined
|
|
36
|
+
|
|
37
|
+
beforeAll(async () => {
|
|
38
|
+
const credentialStore = createCredentialStore(async () => variant.credentials())
|
|
39
|
+
const proxy = createProxy(credentialStore)
|
|
40
|
+
docs = createToolbox(
|
|
41
|
+
'google-docs',
|
|
42
|
+
proxy,
|
|
43
|
+
createIntegrationNode('google-docs', { label: 'Google Docs', credentialId: 'google-docs-creds', credentialVariant: variant.key }),
|
|
44
|
+
variant.key,
|
|
45
|
+
)
|
|
46
|
+
drive = createToolbox(
|
|
47
|
+
'google-drive',
|
|
48
|
+
proxy,
|
|
49
|
+
createIntegrationNode('google-drive', { label: 'Google Drive', credentialId: 'google-drive-creds', credentialVariant: variant.key }),
|
|
50
|
+
variant.key,
|
|
51
|
+
)
|
|
33
52
|
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
const folder = await drive.write('create_folder')({ name: `CmdTest Docs ${Date.now()}` })
|
|
54
|
+
folderId = folder?.id
|
|
55
|
+
expect(folderId).toBeTruthy()
|
|
36
56
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
57
|
+
const created = await drive.write('create_file')({
|
|
58
|
+
name: `CmdTest Doc ${Date.now()}`,
|
|
59
|
+
mimeType: 'application/vnd.google-apps.document',
|
|
60
|
+
parentId: folderId,
|
|
61
|
+
})
|
|
62
|
+
documentId = created?.id
|
|
63
|
+
expect(documentId).toBeTruthy()
|
|
64
|
+
}, 60000)
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
expect(result?.documentId || result?.body?.content || result?.title).toBeTruthy()
|
|
53
|
-
}, 30000)
|
|
66
|
+
afterAll(async () => {
|
|
67
|
+
if (!folderId)
|
|
68
|
+
return
|
|
69
|
+
await safeCleanup(async () => documentId ? drive.write('delete_file')({ fileId: documentId }) : Promise.resolve())
|
|
70
|
+
await safeCleanup(async () => drive.write('delete_file')({ fileId: folderId }))
|
|
71
|
+
}, 60000)
|
|
54
72
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}, 30000)
|
|
73
|
+
it('get_document returns metadata/content', async () => {
|
|
74
|
+
if (!documentId)
|
|
75
|
+
return expect(true).toBe(true)
|
|
76
|
+
const handler = docs.read('get_document')
|
|
77
|
+
const result = await handler({ documentId })
|
|
78
|
+
expect(result?.documentId || result?.body?.content || result?.title).toBeTruthy()
|
|
79
|
+
}, 30000)
|
|
63
80
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
it('get_document_text returns plain text', async () => {
|
|
82
|
+
if (!documentId)
|
|
83
|
+
return expect(true).toBe(true)
|
|
84
|
+
const handler = docs.read('get_document_text')
|
|
85
|
+
const result = await handler({ documentId })
|
|
86
|
+
expect(typeof result?.text === 'string').toBe(true)
|
|
87
|
+
}, 30000)
|
|
88
|
+
|
|
89
|
+
it('get_document_structured returns body JSON', async () => {
|
|
90
|
+
if (!documentId)
|
|
91
|
+
return expect(true).toBe(true)
|
|
92
|
+
const handler = docs.read('get_document_structured')
|
|
93
|
+
const result = await handler({ documentId })
|
|
94
|
+
expect(result?.body || result?.documentId).toBeTruthy()
|
|
95
|
+
}, 30000)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
72
98
|
})
|
|
@@ -1,34 +1,9 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
import { fileURLToPath } from 'node:url'
|
|
4
1
|
import { describe, expect, it } from 'vitest'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
function escapeRegExp(str: string): string {
|
|
8
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
9
|
-
}
|
|
2
|
+
import { getMissingToolUsages } from '../../__tests__/usageParity.js'
|
|
10
3
|
|
|
11
4
|
describe('google-docs static usage parity', () => {
|
|
12
|
-
it('every manifest tool is referenced in tests
|
|
13
|
-
const
|
|
14
|
-
const toolNames = (manifest.tools as any[]).map(t => t.name)
|
|
15
|
-
|
|
16
|
-
const testsDir = fileURLToPath(new URL('.', import.meta.url))
|
|
17
|
-
expect(existsSync(testsDir)).toBe(true)
|
|
18
|
-
const testFiles = readdirSync(testsDir)
|
|
19
|
-
.filter(f => /\.test\.(t|j)s$/.test(f) && !f.includes('usage_parity.test'))
|
|
20
|
-
.map(f => resolve(testsDir, f))
|
|
21
|
-
|
|
22
|
-
const fileContents = testFiles.map(f => readFileSync(f, 'utf8'))
|
|
23
|
-
|
|
24
|
-
const missing: string[] = []
|
|
25
|
-
for (const name of toolNames) {
|
|
26
|
-
const nameRe = new RegExp(`build(?:Read|Write|Admin)?(?:Handler)?\\(\\s*['\"\`]${escapeRegExp(name)}['\"\`]\\s*\\)`, 'm')
|
|
27
|
-
const found = fileContents.some(src => nameRe.test(src))
|
|
28
|
-
if (!found)
|
|
29
|
-
missing.push(name)
|
|
30
|
-
}
|
|
31
|
-
|
|
5
|
+
it('every manifest tool is referenced in tests', () => {
|
|
6
|
+
const missing = getMissingToolUsages({ integrationName: 'google-docs', importMetaUrl: import.meta.url })
|
|
32
7
|
expect(missing, `Missing handler usages in tests: ${missing.join(', ')}`).toEqual([])
|
|
33
8
|
})
|
|
34
9
|
})
|