Skip to content

Commit f7f3f04

Browse files
authored
Merge pull request #4 from usdigitalresponse/kevee/missing-docs
Add missing docs to readme
2 parents ca32728 + 91f4f96 commit f7f3f04

File tree

9 files changed

+99
-13
lines changed

9 files changed

+99
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
- Removed the `__sdk.js` developer file from the respoitory.
11+
- Fixed the types for runAirtableScript.
1112

1213
## [0.0.2] - 2025-01-09
1314

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,47 @@ const result = await runAirtableScript({
118118

119119
You can pass one of `us`, `friendly`, `european`, or `iso`.
120120

121+
### Mocking fetch requests
122+
123+
Airtable scripts can either use `fetch`, or in extensions `remoteFetchAsync` to make HTTP requests. You can mock these requests using the `fetchMock` setting:
124+
125+
```js
126+
const result = await runAirtableScript({
127+
script: myScript,
128+
base: baseFixture,
129+
fetchMock: (url, request) => {
130+
return {
131+
status: 200,
132+
body: JSON.stringify({ message: 'Hello, world!' }),
133+
}
134+
},
135+
})
136+
```
137+
138+
### Mocking user inputs
139+
140+
You can mock any `input` from either an automation input or user interaction using the `mockInput` setting:
141+
142+
```js
143+
const results = await runAirtableScript({
144+
script: `
145+
const text = await input.textAsync('Select a table')
146+
output.inspect(text)
147+
`,
148+
base: randomRecords,
149+
mockInput: {
150+
// @ts-ignore
151+
textAsync: (label) => {
152+
if (label === 'Select a table') {
153+
return 'text123'
154+
}
155+
},
156+
},
157+
})
158+
```
159+
160+
Every [input method for extensions or automations](https://airtable.com/developers/scripting/api/input) are available to be mocked. Check out the [input.test.ts](./test/input.test.ts) file for examples.
161+
121162
### Results
122163

123164
The results from calling `runAirtableScript` are an object with several properties:

src/environment/console-aggregator.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ type ConsoleAggregator = {
1313
/**
1414
* Returns a console object that aggregates all messages logged to it.
1515
* Used to override the global console object in tests.
16+
*
17+
* The _getMessages method is called after a test is run to pass the
18+
* messages to the test runner.
1619
*/
1720
const consoleAggregator = (): ConsoleAggregator => {
1821
const consoleMessages: ConsoleMessage[] = []

src/environment/index.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@ import { OUTPUT_CLEAR } from './output-clear'
1212

1313
type StrictGlobal = {
1414
runAirtableScript: (options: RunScriptOptions) => Promise<RunScriptResult>
15-
MutationTypes: typeof MutationTypes | undefined
16-
OUTPUT_CLEAR: typeof OUTPUT_CLEAR | undefined
15+
MutationTypes: typeof MutationTypes
16+
OUTPUT_CLEAR: typeof OUTPUT_CLEAR
1717
}
1818

1919
export type AirtableScriptGlobal = Required<StrictGlobal>
2020

2121
export class AirtableScriptEnvironment extends NodeEnvironment {
22-
declare global: StrictGlobal & NodeEnvironment['global']
23-
2422
constructor(config: JestEnvironmentConfig, _context: EnvironmentContext) {
2523
super(config, _context)
2624
this.global.runAirtableScript = runAirtableScript

src/environment/run-airtable-script.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111

1212
type DefaultDateLocale = 'friendly' | 'us' | 'european' | 'iso'
1313

14+
type Output = [string, number, boolean] | { key: string; value: string }[]
15+
1416
type RunScriptOptions = {
1517
script: string
1618
base: { base: unknown } | unknown
@@ -24,7 +26,7 @@ type RunScriptOptions = {
2426
}
2527

2628
type RunScriptResult = {
27-
output: unknown[]
29+
output: Output
2830
mutations: Mutation[]
2931
console: ConsoleMessage[]
3032
}
@@ -47,6 +49,9 @@ type RunContext = {
4749

4850
let sdkScript: string | null = null
4951

52+
/**
53+
* Runs a given Airtable script against a base fixture. Full definition is in src/environment/index.ts
54+
*/
5055
const runAirtableScript = async ({
5156
script,
5257
base,
@@ -77,8 +82,8 @@ const runAirtableScript = async ({
7782
__defaultDateLocale: defaultDateLocale,
7883
console: consoleAggregator(),
7984
}
80-
vm.createContext(context)
8185

86+
vm.createContext(context)
8287
vm.runInContext(sdkScript, context)
8388
// We need to run the script in an async function so that we can use await
8489
// directly inside the script.
@@ -90,7 +95,7 @@ const runAirtableScript = async ({
9095
)
9196

9297
return {
93-
output: context.__output || [],
98+
output: (context.__output as Output) || [],
9499
mutations: context.__mutations || [],
95100
console: context.console._getMessages(),
96101
}

src/environment/sdk/globals/output.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,18 @@ type ExtensionOutput = {
2020
// @ts-ignore
2121
globalThis.__output = []
2222

23+
/**
24+
* The output object if a script is being used within an automation.
25+
*/
2326
const automationOutput: AutomationOutput = {
2427
set: (key, value) => {
2528
__output.push({ key, value })
2629
},
2730
}
2831

32+
/**
33+
* The output object if a script is being used within an extension.
34+
*/
2935
const extensionOutput: ExtensionOutput = {
3036
/**
3137
* Displays the given text on-screen.
@@ -88,6 +94,7 @@ const extensionOutput: ExtensionOutput = {
8894
},
8995
}
9096

97+
// Use one of the two outputs based on the context (extension or automation)
9198
const output: AutomationOutput | ExtensionOutput = globalThis.__inAutomation
9299
? automationOutput
93100
: extensionOutput

src/environment/sdk/lib/pascal-case.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
2-
* A pascal case utility function.
2+
* A pascal case utility function. Used for schema IDs, which always start with
3+
* a three-letter lower-case prefix like tblTableId or fldFieldId.
34
*/
45
const pascalCase = (str: string): string =>
56
str

src/index.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
11
export { AirtableScriptEnvironment as default } from './environment'
22

33
import type { AirtableScriptGlobal } from './environment'
4+
import type {
5+
RunScriptOptions,
6+
RunScriptResult,
7+
} from './environment/run-airtable-script'
48

59
declare global {
6-
const runAirtableScript: AirtableScriptGlobal['runAirtableScript']
10+
/**
11+
* Runs a given Airtable script against a base fixture. Returns the output, console, and base
12+
* mutations that the script generated.
13+
*
14+
* @param {RunScriptOptions} options
15+
* @param {string} options.script The script to run, as a string.
16+
* @param {Base} options.base The base fixture to run the script against. Generate this using
17+
* the Test Fixture Generator extension.
18+
* @param {boolean} [options.inAutomation=false] Whether the script is running in an automation. Defaults to false.
19+
* @param {DefaultCursor | false} [options.defaultCursor=false] The default cursor to use for the script. Defaults to false.
20+
* @param {Collaborator | false} [options.currentUser=false] The current user to use for the script. Defaults to false.
21+
* @param {unknown} [options.mockInput=undefined] The mock input for the script. See the README for more information.
22+
* @param {Function | false} [options.mockFetch=false] A function that mocks any fetch requests.
23+
* @param {DefaultDateLocale} [options.defaultDateLocale='us'] The date format to use when a date field uses the "local" date format. Defaults to 'us'.
24+
* @returns {Promise<RunScriptResult>}
25+
*/
26+
const runAirtableScript: (
27+
options: RunScriptOptions
28+
) => Promise<RunScriptResult>
29+
/**
30+
* An object containing the different types of mutations that can be tracked in a script.
31+
*/
732
const MutationTypes: AirtableScriptGlobal['MutationTypes']
33+
/**
34+
* A special string that is used to denote that a call to output.clear() was made in the script.
35+
*/
836
const OUTPUT_CLEAR: AirtableScriptGlobal['OUTPUT_CLEAR']
937
}

test/input.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ describe('Input', () => {
1515
config: () => ({ [key]: 'tbl123' }),
1616
},
1717
})
18-
expect(results.output[0].key).toEqual('config')
19-
expect(results.output[0].value).toEqual(
20-
JSON.stringify({ [key]: 'tbl123' })
21-
)
18+
if (typeof results.output[0] === 'object') {
19+
expect(results.output[0].key).toEqual('config')
20+
expect(results.output[0].value).toEqual(
21+
JSON.stringify({ [key]: 'tbl123' })
22+
)
23+
}
2224
})
2325
})
2426
describe('extension script', () => {

0 commit comments

Comments
 (0)