A calm place to write long-form, and publish it to the open social web.
skypress.blog/
1import { describe, it, expect, beforeEach } from 'vitest';
2import { createDraftStore, type WriteDraft } from './draft-store';
3import { createMemoryAssetStore } from './asset-store';
4import type { BlockNode } from '../blocks/render';
5
6const DATA = 'data:image/png;base64,QUFB';
7
8function draft(): WriteDraft {
9 return {
10 title: 'Hello',
11 lede: 'A lede',
12 blocks: [
13 { name: 'core/paragraph', attributes: { content: 'hi' }, innerBlocks: [] },
14 { name: 'core/image', attributes: { url: DATA }, innerBlocks: [] },
15 ] as BlockNode[],
16 coverDataUrl: DATA,
17 };
18}
19
20beforeEach( () => window.localStorage.clear() );
21
22function newStore() {
23 return createDraftStore( { assets: createMemoryAssetStore(), storage: window.localStorage } );
24}
25
26describe( 'draft-store', () => {
27 it( 'round-trips a draft including held image + cover bytes', async () => {
28 const store = newStore();
29 await store.save( draft() );
30 // Image bytes must NOT sit in localStorage (only the token skeleton).
31 expect( window.localStorage.getItem( 'skypress:write:draft' ) ).not.toContain( 'base64' );
32 const loaded = await store.load();
33 expect( loaded ).toEqual( draft() );
34 } );
35
36 it( 'returns null when nothing is saved', async () => {
37 expect( await newStore().load() ).toBe( null );
38 } );
39
40 it( 'clear() removes the draft and its assets', async () => {
41 const store = newStore();
42 await store.save( draft() );
43 await store.clear();
44 expect( await store.load() ).toBe( null );
45 } );
46
47 it( 'publish intent is one-shot (set, then consumed once)', () => {
48 const store = newStore();
49 expect( store.consumePublishIntent() ).toBe( false );
50 store.setPublishIntent();
51 expect( store.consumePublishIntent() ).toBe( true );
52 expect( store.consumePublishIntent() ).toBe( false );
53 } );
54} );