* Add resilient PDF thumbnails to GUI uploads * Keep GUI image thumbnails working with SDKs lacking the callback context The desktop loads puter.js from js.puter.com by default, and the SDK there predates the thumbnail callback context, so passing the PDF generator made every image upload lose its thumbnail until the SDK deploys. Fall back to the SDK's bundled image generator whenever the running SDK passes no usable context, and cover both paths in the unit and browser tests. * Ignore preparation failures that land after an upload is cancelled Cancelling during preparation already rejects the upload and fires the abort callback. If the step that was in flight then fails, such as a dropped directory that cannot be read, the error callback also fired and the GUI showed an upload error for an upload the user had just cancelled. Skip error reporting once preparation has been aborted. * Give each PDF thumbnail worker four seconds The per-PDF budget covers downloading PDF.js as well as rendering, and the first PDF of a session on a slower connection ran out of time before its assets had even loaded. Four seconds fits that first load on ordinary connections while staying under the five-second batch cap, so one stuck PDF still leaves the rest of the batch a chance.
puter.js API test environment
Client-agnostic test suites for puter.js, run against a self-contained
in-memory Puter server — no external server, no stdout password scraping,
no .env. The same suite files execute on three platforms through thin
adapters:
| Runner | Platform | How the SDK runs |
|---|---|---|
runners/node.test.ts |
node.js | Built SDK bundle loaded into a fresh vm context per test (like src/init.cjs) |
runners/browser.test.ts |
headless Chromium (playwright) | Fixture page served same-origin on the API host loads /puter.js/v2 from the server itself |
runners/workerd.test.ts |
local workerd (Miniflare) | Suite bundle deployed as a real Puter worker via puter.workers.create, dispatched through the local worker proxy |
Running
Build the SDK bundle and worker preamble once (repeat after SDK changes):
npm run build:workerLib
Then, from the package root:
npm run test:puterjs # all three platforms
npm run test:puterjs:node
npm run test:puterjs:browser # needs `npx playwright install chromium` once
npm run test:puterjs:workerd
How it works
Each runner boots setupPuterTestEnv() (from src/backend/testUtil.ts) in
beforeAll: a fully in-memory backend (sqlite / dynalite / redis-mock /
fauxqs S3) listening on a real ephemeral port, with the production
extensions loaded and two deterministic users seeded:
admin— member of the admin group,testuser— a regular, non-privileged user (what suites run as).
The env manifest ({ origin, apiOrigin, users } with fixed passwords and
pre-minted session tokens) is JSON-serializable and crosses into whatever
runtime executes the tests. Root-only routes (e.g. POST /login) live on
origin; the SDK talks to apiOrigin (the api. subdomain host).
Adding tests
Tests are added once and run on all three platforms — never write a per-platform test here.
- Existing area (apps, auth, fs, kv): add a test to the matching
suites/<name>.suite.ts— one entry in the object, key is the test name, value gets the contextt. - New area (e.g. hosting): create
suites/hosting.suite.tsand register it insuites/index.ts(explicit list, no globbing — esbuild bundles exactly this list for the browser/workerd runners).
import { suite } from '../harness/types.ts';
export default suite('example', {
'does the thing': async (t) => {
await t.puter.fs.write(`/${t.env.users.user.username}/x.txt`, 'hi');
t.assert.ok(await t.puter.fs.stat(/* … */));
},
});
Rules that keep a suite runnable everywhere:
- Platform-agnostic only. No node/browser/workerd-specific imports —
a suite may use the SDK instance (
t.puter, authed as the regular user), globalfetch, andt.assert(ok/equal/deepEqual/rejects). - Admin or cross-user assertions go through plain
fetchwitht.env.users.admin.token(seeauth.suite.ts) — that works identically on every platform. - Unique resource names per test (file paths, kv keys): tests in a suite share one server and one user, so don't reuse names across tests.
- The runners in
runners/enumerate suites automatically — adding a suite requires no runner changes.
Iterate fast with npm run test:puterjs:node (boots in ~3s); run
npm run test:puterjs before pushing to cover browser and workerd too.