miniflare
miniflare copied to clipboard
Feat: add getMiniflareDurableObjectState function for instantiating DurableObjectState
At the moment, miniflare supports testing durable object stubs. However, I'd like to instantiate a durable object class and unit test the non-fetch() methods.
At the moment, this is accomplishable but could be more ergonomic. After looking at the miniflare source, I was able to put together the following:
import { DurableObjectState } from '@miniflare/durable-objects';
import { Campaign } from '../src/campaign'; // assume this is a class that implements DurableObject
const env = getMiniflareBindings();
const id = env.CAMPAIGN.newUniqueId();
describe('Campaign', () => {
let storage: DurableObjectStorage;
let campaign: Campaign;
beforeAll(async () => {
storage = await getMiniflareDurableObjectStorage(id);
});
beforeEach(() => {
campaign = new Campaign(new DurableObjectState(id as any, storage as any), env);
});
test('getPeople', async () => {
expect(await campaign.getPeople()).toBe(0);
storage.put('totalPeople', 2);
expect(await campaign.getPeople()).toBe(2);
});
});
Notice the need to cast to any in new DurableObjectState(id as any, storage as any) (because the DurableObjectId returned from DurableObjectNamespace#newUniqueId() is not the same DurableObjectId typescript type that DurableObjectState expects. Also note that I had to look in the miniflare source to figure out how to instantiate new DurableObjectState().
An improvement would be exposing a getMiniflareDurableObjectState() function like the following:
function getMiniflareDurableObjectState(
id: DurableObjectId,
): Promise<DurableObjectState>;
function getMiniflareDurableObjectState(
id: DurableObjectId,
storage: DurableObjectStorage,
): DurableObjectState;
function getMiniflareDurableObjectState(
id: DurableObjectId,
storage?: DurableObjectStorage,
) {
if (!storage) {
return getMiniflareDurableObjectStorage(id).then(
(s) => new DurableObjectState(id as any, s as any),
);
}
return new DurableObjectState(id as any, storage as any);
}
Usage like
import { DurableObjectState } from '@miniflare/durable-objects';
import { Campaign } from '../src/campaign'; // assume this is a class that implements DurableObject
const env = getMiniflareBindings();
const id = env.CAMPAIGN.newUniqueId();
describe('Campaign', () => {
let storage: DurableObjectStorage;
let campaign: Campaign;
beforeAll(async () => {
storage = await getMiniflareDurableObjectStorage(id);
});
beforeEach(async () => {
campaign = new Campaign(getMiniflareDurableObjectState(id, storage), env);
// or
campaign = new Campaign(await getMiniflareDurableObjectState(id), env);
});
});
Hey! 👋 I agree, this isn't pretty and should definitely be easier. We'll try sort something out for the next version... 👍
Note: while previously I was able to create my own getMiniflareDurableObjectState() function to test non-fetch methods, at some point in the past month this appears to have been broken. See issue #184. It's unclear what has caused this regression and I haven't actually been able to recreate a "working" getMiniflareDurableObjectState()--even when using previous versions of the miniflare library.
Edit: I've confirmed that this is a regression.
Hey! 👋 Miniflare 2.9.0 has just been released, which implements this change. You can find the full changelog here.