Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.3.0] - 2026-08-02

### Added

- `examples/field-types`: a workbench extension covering every `FieldType`, with a smoke suite that validates each type's documented cell read format against the SDK and each editor's mutations against the documented write format.
- `fixtures/field-types.ts`: a fixture with every creatable Airtable field type and full option permutations, generated from a real base.
- The fixture generator warns when exporting `multipleLookupValues` fields: the REST API flattens lookups, so the documented `Array<{linkedRecordId, value}>` shape needs hand-editing.

### Fixed

- Reading a `multipleLookupValues` cell no longer throws: fixtures now declare lookups in the SDK's documented read format, and the test driver initializes the SDK accordingly (`isUsingNewLookupCellValueFormat`).

## [0.2.0] - 2026-08-01

### Changed
Expand Down
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ npm workspaces monorepo:
- `packages/testing` — `@usdr/airtable-interface-testing`: the `TestDriver` library.
- `packages/fixture-generator` — `@usdr/airtable-interface-testing-fixtures`: CLI that exports a real base to fixture files via the Airtable REST API.
- `examples/todo-list` — example extension + consumer-style Jest suite; doubles as integration test and documentation.
- `examples/field-types` — workbench extension + data-driven smoke suite covering every `FieldType`'s documented cell read/write formats, built on `fixtures/field-types.ts` (generated from a real base) extended with the eight read-only types the Meta API can't create.
- `_blocks/` (gitignored) — reference checkouts of the `v1` and `interface-alpha` branches of Airtable/blocks. Read-only reference; never a build input.

## Commands
Expand All @@ -52,6 +53,8 @@ npm workspaces monorepo:
## Known constraints

- Pinned/validated SDK build: `@airtable/blocks@interface-alpha` = `0.0.0-experimental-8575f0e0d-20260428` — the tag Airtable's own extension templates install, so it's what most consumers have. The suite also passes against `interface-alpha-next`. A new experimental build can move internals; the library fails loudly at import if the dist files vanish. Update the README's validated-version note when bumping.
- **The two builds differ in their record-loading model:** the pinned `interface-alpha` build has NO `table.selectRecords()`/query-result API — its `useRecords(table)` reads the record store synchronously from `recordsById`/`recordOrder`. `interface-alpha-next` introduced query results + `loadDynamicQueryAsync` (which is why the mock implements it; it's simply never called on the older build). Tests that need Record models portably should collect them through `useRecords` in a rendered component, not `selectRecords`.
- **Lookup cell values:** the fixture converter sets `isUsingNewLookupCellValueFormat: true` in SdkInitData, so fixtures declare `multipleLookupValues` cells in the SDK's documented public read format `Array<{linkedRecordId, value}>`. Without that flag the SDK expects hyperbase's internal shape and `getCellValue` throws. The generator CLI cannot produce the documented shape (the REST API flattens lookups) — it passes values through with a warning.
- **The two builds differ in their `exports` map:** `interface-alpha-next` exports `./package.json`, `interface-alpha` does not. `resolveSdkRoot()` in `src/sdk_internals.ts` therefore tries `./package.json` first and falls back to resolving `@airtable/blocks/interface/ui` and walking up to the owning directory. Don't "simplify" it back to a single `require.resolve('@airtable/blocks/package.json')` — that breaks `interface-alpha` entirely.
- Changing the SDK dist-tag needs the lockfile entry dropped to take effect: npm won't re-resolve (or downgrade) a dist-tag spec on its own. Edit both workspaces' `package.json`, delete `packages['node_modules/@airtable/blocks']` from `package-lock.json`, then `npm install`.
- The SDK's published ESM uses extensionless relative imports → **only runs under a transforming runner** (Jest+babel validated; Vitest plausible, unvalidated; plain Node impossible). Don't chase plain-Node support.
Expand All @@ -67,6 +70,8 @@ Security rules adapted from [TikiTribe/claude-secure-coding-rules](https://githu

## Work log

- **2026-08-02** — Version 0.3.0: all five `package.json` files bumped in lockstep, CHANGELOG.md entry added (field-types example + fixture, lookup read-format fix, generator lookup warning), release-URL examples in the four docs moved to v0.3.0. Release goes out via tag-on-merge when this lands on `main`.
- **2026-08-02** — Added `examples/field-types`: a list-and-edit workbench over both fixture tables with per-FieldType editors, plus a smoke suite that iterates the SDK's `FieldType` enum and validates every cell value against the documented read format and every editor mutation against the documented write format (79 tests). Enabling it surfaced two real fixes: the converter now sets `isUsingNewLookupCellValueFormat: true` (fixtures use the documented lookup shape; without the flag `getCellValue` throws on lookups), and the generator warns that REST lookups export flat. `fixtures/field-types.ts` corrected accordingly (lookup shape, collaborator coverage). Learned: the pinned `interface-alpha` build has no `selectRecords` API — see Known constraints.
- **2026-08-01** — All four `package.json` files bumped to 0.2.0 and kept in lockstep from now on: `scripts/check-versions.mjs` (root script `check:versions`) fails when any two disagree, wired into ci.yml before lint and release.yml before the tag guard. A `testing` 0.2.0 / `fixture-generator` 0.1.0 split is what broke the first release. Release-URL examples in all four docs moved to v0.2.0; the earlier "root stays at 0.0.0" guidance is retired.

- **2026-07-23** — Switched the pinned SDK from `interface-alpha-next` to `interface-alpha` (what Airtable's templates install). Required a real fix: `interface-alpha` doesn't export `./package.json`, so `sdk_internals.ts` gained `resolveSdkRoot()` with an entry-point fallback. Full suite verified green against both dist-tags.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ You get a `TestDriver` with the same shape as the v1 library — fixture data in
These packages aren't on npm yet — we attach tarballs to [GitHub Releases](https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases) instead. Open the latest release, copy the link to the `.tgz` you want under **Assets**, and hand it to npm:

```bash
npm install --save-dev https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases/download/v0.2.0/usdr-airtable-interface-testing-0.2.0.tgz
npm install --save-dev https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases/download/v0.3.0/usdr-airtable-interface-testing-0.3.0.tgz
```

Release assets always follow the same shape, so you can bump the version in that URL directly:
Expand All @@ -42,6 +42,8 @@ npm writes the URL into your lockfile, so installs stay reproducible. [Getting s

**[examples/todo-list](examples/todo-list) ---** a small interface extension with a complete test suite. If you want to see the library in use before reading docs, read [its test file](examples/todo-list/test/app.test.tsx).

**[examples/field-types](examples/field-types) ---** a workbench extension covering every `FieldType`, with a data-driven smoke suite asserting each type's documented cell read and write formats. The reference for "what does this field type's cell value look like?"

## Quick start for working in this project

If you want to work on the actual testing repo itself:
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ For a live example, check out the [Example extension](../examples/todo-list).
This package isn't on npm yet — we publish tarballs on [GitHub Releases](https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases) instead. After setting up your Airtable project, install the latest release:

```bash
npm install --save-dev https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases/download/v0.2.0/usdr-airtable-interface-testing-0.2.0.tgz
npm install --save-dev https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases/download/v0.3.0/usdr-airtable-interface-testing-0.3.0.tgz
```

**Finding the URL ---** open the [releases page](https://github.com/usdigitalresponse/airtable-interface-extension-testing/releases), pick a release, and look under **Assets**. Copy the link address of `usdr-airtable-interface-testing-<version>.tgz` — that's the URL you pass to `npm install`. The URLs always follow the same pattern, so you can also just edit the version in the command above:
Expand Down Expand Up @@ -74,14 +74,14 @@ Every test follows the same four-step pattern: create a test driver from fixture

### 1. Create a test driver with fixture data

Each test starts by instantiating a `TestDriver` with fixture data. We suggest saving this as a single file for resuse.
Each test starts by instantiating a `TestDriver` with fixture data. We suggest saving this as a single file for reuse.

```tsx
import TestDriver from "@usdr/airtable-interface-testing";
import fixtureData from "./fixtures/my-base";

const testDriver = new TestDriver(fixtureData);
export testDriver
export default testDriver;
```

### 2. Render the extension
Expand Down
17 changes: 17 additions & 0 deletions examples/field-types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Field types example

A workbench extension covering **every [FieldType](https://airtable.com/developers/interface-extensions/api/FieldType)**, used as a smoke test for all cell value formats. If you want to know what a given field type's cell value looks like — or how to write one back — this example is the reference.

The app lists every record of every table in the base and renders a type-appropriate editor for each field: text inputs for the string family (committing on blur), selects and checkbox groups for choices, cross-table checkboxes for record links, an append-by-URL control for attachments, and plain text for the read-only computed types (formula, rollup, count, lookups, barcode, button, and the created/modified metadata fields).

Two suites keep it honest:

**[format_coverage.test.tsx](test/format_coverage.test.tsx) ---** iterates the SDK's own `FieldType` enum and asserts the fixture contains every type, and that every cell value read through the real SDK matches that type's documented **cell read format**. If Airtable adds a field type, this suite fails until the fixture covers it — that's the point.

**[app.test.tsx](test/app.test.tsx) ---** renders the UI and edits a representative field of each editable kind, asserting the emitted mutations carry the documented **cell write format** (`{id}` for selects, `Array<{id, name}>` for record links, appended `{url}` for attachments, and so on).

The fixture comes from [fixtures/field-types.ts](../../fixtures/field-types.ts) — generated from a real base holding every field type the Meta API can create — extended in [test/fixtures.ts](test/fixtures.ts) with the eight read-only types the API cannot create (autoNumber, button, createdTime, lastModifiedTime, createdBy, lastModifiedBy, externalSyncSource, aiText).

```bash
npm test
```
3 changes: 3 additions & 0 deletions examples/field-types/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
preset: '@usdr/airtable-interface-testing',
};
23 changes: 23 additions & 0 deletions examples/field-types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@usdr/example-field-types",
"private": true,
"version": "0.3.0",
"description": "Example Airtable interface extension covering every FieldType, used as a smoke test for all cell value formats",
"type": "module",
"scripts": {
"test": "jest",
"types": "tsc"
},
"dependencies": {
"@airtable/blocks": "interface-alpha",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@usdr/airtable-interface-testing": "*",
"typescript": "^5.6.0"
}
}
Loading
Loading