Skip to content

Commit

Permalink
chore: test cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Akolyte01 committed Aug 16, 2023
1 parent daaa643 commit 28a6ea1
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 105 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ notes:
- all mapping load functions are rebounced by default
- if an async store loses all subscriptions and then gains one the mapping load function will always evaluate even if the inputs have not changed
- can't use stores to hold errors
- rebounce clear is now called abort

## 1.0.17 (2023-6-20)

Expand Down
146 changes: 50 additions & 96 deletions test/async-stores/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
writable,
safeLoad,
} from '../../src';
import { delayValue, delayFunction } from '../helpers';

describe('asyncWritable', () => {
const writableParent = writable('writable');
Expand Down Expand Up @@ -83,7 +84,7 @@ describe('asyncWritable', () => {
});

describe('one parent asyncDerived', () => {
it('loads expected value NOMERGE', async () => {
it('loads expected value', async () => {
const myAsyncDerived = asyncDerived(writableParent, (storeValue) =>
Promise.resolve(`derived from ${storeValue}`)
);
Expand Down Expand Up @@ -189,7 +190,7 @@ describe('asyncWritable', () => {
expect(mockReload).toHaveBeenCalledTimes(2);
});

it('rejects load when parent load fails', () => {
it('rejects load and reload when parent load fails', () => {
const asyncReadableParent = asyncReadable(
undefined,
() => Promise.reject(new Error('error')),
Expand All @@ -207,21 +208,6 @@ describe('asyncWritable', () => {
expect(myAsyncDerived.reload()).rejects.toStrictEqual(new Error('error'));
});

it('rejects reload when parent load fails', () => {
const asyncReadableParent = asyncReadable(undefined, () =>
Promise.reject(new Error('error'))
);
expect(asyncReadableParent.load()).rejects.toStrictEqual(
new Error('error')
);

const myAsyncDerived = asyncDerived(asyncReadableParent, (storeValue) =>
Promise.resolve(`derived from ${storeValue}`)
);

expect(myAsyncDerived.load()).rejects.toStrictEqual(new Error('error'));
});

it('correctly unsubscribes from parents', async () => {
const writableParent = writable('initial');
const firstDerivedLoad = vi.fn(($parent) =>
Expand All @@ -242,7 +228,7 @@ describe('asyncWritable', () => {

// this sucks but I can't figure out a better way to wait for the
// subscribe callbacks to get called without generating a new subscription
await new Promise((resolve) => setTimeout(resolve, 100));
await delayValue(null, 100);

expect(firstValue).toBe('initial first');
expect(secondValue).toBe('initial second');
Expand All @@ -252,7 +238,7 @@ describe('asyncWritable', () => {
firstUnsubscribe();
writableParent.set('updated');

await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);

expect(firstValue).toBe('initial first');
expect(secondValue).toBe('updated second');
Expand All @@ -262,11 +248,7 @@ describe('asyncWritable', () => {

describe('abort/rebounce integration', () => {
it('loads to rebounced value only', async () => {
const load = (value: string) => {
return new Promise<string>((resolve) =>
setTimeout(() => resolve(value), 100)
);
};
const load = (value: string) => delayValue(value, 100);

const myParent = writable();
const { store: myStore, state: myState } = asyncDerived(myParent, load);
Expand All @@ -286,14 +268,15 @@ describe('asyncWritable', () => {
});

myParent.set('a');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
expect(get(myState).isLoading).toBe(true);

myParent.set('b');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
expect(get(myState).isLoading).toBe(true);

myParent.set('c');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
expect(get(myState).isLoading).toBe(true);

const finalValue = await myStore.load();
Expand Down Expand Up @@ -334,13 +317,15 @@ describe('asyncWritable', () => {
});

myParent.set('a');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
expect(get(myState).isLoading).toBe(true);

myParent.set('b');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
expect(get(myState).isLoading).toBe(true);

myParent.set('c');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
expect(get(myState).isLoading).toBe(true);

const finalValue = await myStore.load();
Expand All @@ -355,9 +340,7 @@ describe('asyncWritable', () => {
let timesCalled = 0;
const load = (value: string) => {
timesCalled += 1;
return new Promise<string>((resolve) =>
setTimeout(() => resolve(value), 200 - timesCalled * 100)
);
return delayValue(value, 200 - timesCalled * 100);
};

const myParent = writable();
Expand All @@ -382,7 +365,7 @@ describe('asyncWritable', () => {
const result = await myStore.load();
expect(result).toBe('b');

await new Promise((resolve) => setTimeout(resolve, 200));
await delayValue(null, 200);
expect(get(myStore)).toBe('b');
expect(setIncorrectly).toBe(false);
expect(get(myState).isLoaded).toBe(true);
Expand All @@ -394,41 +377,34 @@ describe('asyncWritable', () => {
.mockReturnValueOnce('first')
.mockReturnValueOnce('second');

const load = () => {
const valueToReturn = getFinalValue();

return new Promise<string>((resolve) =>
setTimeout(() => resolve(valueToReturn), 100)
);
};

const myLoadable = asyncReadable('initial', load, {
reloadable: true,
});
const myLoadable = asyncReadable(
'initial',
delayFunction(getFinalValue, 100),
{
reloadable: true,
}
);

expect(myLoadable.load()).resolves.toBe('second');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
const finalValue = await myLoadable.reload();
expect(finalValue).toBe('second');
});

it('can be aborted correctly', async () => {
const load = (value: string) => {
return new Promise<string>((resolve) =>
setTimeout(() => resolve(value), 100)
);
};

const myParent = writable();
const { store: myStore, state: myState } = asyncDerived(myParent, load);
const { store: myStore, state: myState } = asyncDerived(
myParent,
delayFunction((value) => value, 100)
);

myStore.subscribe(vi.fn());
myParent.set('one');
let loadValue = await myStore.load();
expect(loadValue).toBe('one');

myParent.set('two');
await new Promise((resolve) => setTimeout(resolve, 50));
await delayValue(null, 50);
myStore.abort();

loadValue = await myStore.load();
Expand Down Expand Up @@ -475,7 +451,7 @@ describe('asyncWritable', () => {
it('deterministically sets final value when receiving updates while loading', async () => {
const delayedParent = asyncReadable(
undefined,
() => new Promise((resolve) => setTimeout(resolve, 1000))
delayFunction(() => null, 100)
);
const mockLoad = vi
.fn()
Expand Down Expand Up @@ -520,18 +496,17 @@ describe('asyncWritable', () => {
const parentA = derived(grandParent, (value) => value);
const parentB = asyncDerived(
grandParent,
(value) =>
new Promise((resolve) =>
setTimeout(() => resolve(value.toUpperCase()), 100)
)
delayFunction((value) => value.toUpperCase(), 100)
);
const parentC = asyncDerived(
parentB,
delayFunction((value) => value, 100)
);

const load = vi.fn(
([valueA, valueB]) =>
new Promise((resolve) =>
setTimeout(() => resolve(valueA + valueB), 100)
)
delayFunction(([valueA, valueB]) => valueA + valueB, 100)
);
const myLoadable = asyncDerived([parentA, parentB], load);
const myLoadable = asyncDerived([parentA, parentC], load);
myLoadable.subscribe(vi.fn());

let result = await myLoadable.load();
Expand Down Expand Up @@ -756,10 +731,8 @@ describe('asyncWritable', () => {
);
myAsyncWritable.subscribe(vi.fn());

let value = await myAsyncWritable.load();
expect(value).toBe('first value');
value = await myAsyncWritable.reload();
expect(value).toBe('first value');
expect(await myAsyncWritable.load()).toBe('first value');
expect(await myAsyncWritable.reload()).toBe('first value');
});

it('does reload if reloadable', async () => {
Expand Down Expand Up @@ -800,10 +773,8 @@ describe('asyncWritable', () => {
);
myAsyncWritable.subscribe(vi.fn());

let value = await myAsyncWritable.load();
expect(value).toBe('derived from first value');
value = await myAsyncWritable.reload();
expect(value).toBe('derived from first value');
expect(await myAsyncWritable.load()).toBe('derived from first value');
expect(await myAsyncWritable.reload()).toBe('derived from first value');
});

it('can access asyncReadable parent loaded value while writing', async () => {
Expand Down Expand Up @@ -868,7 +839,7 @@ describe('asyncWritable', () => {
expect(get(myAsyncWritable)).toBe('derived from first value');
await myAsyncWritable.reload();
expect(get(myAsyncWritable)).toBe('derived from second value');
expect(myAsyncWritable.load()).resolves.toBe('derived from second value');
expect(await myAsyncWritable.load()).toBe('derived from second value');

await myAsyncWritable.set('set value');
expect(get(myAsyncWritable)).toBe('set value');
Expand Down Expand Up @@ -1021,7 +992,7 @@ describe('trackState', () => {
});
});

describe('adds state store when trackState enabled', () => {
describe('adds state store', () => {
it('works with asyncWritable', async () => {
const { store: myStore, state: myState } = asyncWritable(
[],
Expand All @@ -1033,9 +1004,7 @@ describe('trackState', () => {
expect(get(myStore)).toBe('initial');
expect(get(myState).isLoading).toBe(true);

const result = await myStore.load();

expect(result).toBe('loaded value');
expect(await myStore.load()).toBe('loaded value');
expect(get(myState).isLoaded).toBe(true);
});

Expand All @@ -1049,9 +1018,7 @@ describe('trackState', () => {
expect(get(myStore)).toBe('initial');
expect(get(myState).isLoading).toBe(true);

const result = await myStore.load();

expect(result).toBe('loaded value');
expect(await myStore.load()).toBe('loaded value');
expect(get(myState).isLoaded).toBe(true);
});

Expand All @@ -1065,9 +1032,7 @@ describe('trackState', () => {
expect(get(myStore)).toBe('initial');
expect(get(myState).isLoading).toBe(true);

const result = await myStore.load();

expect(result).toBe('loaded value');
expect(await myStore.load()).toBe('loaded value');
expect(get(myState).isLoaded).toBe(true);
});
});
Expand Down Expand Up @@ -1164,10 +1129,7 @@ describe('trackState', () => {
const myParent = writable('initial');
const { store: myStore, state: myState } = asyncDerived(
myParent,
($myParent) =>
new Promise((resolve) =>
setTimeout(() => resolve(`derived from ${$myParent}`), 50)
),
delayFunction(($myParent) => `derived from ${$myParent}`, 50),
{ trackState: true }
);

Expand All @@ -1181,7 +1143,6 @@ describe('trackState', () => {
expect(get(myState).isLoaded).toBe(true);

myParent.set('updated');
await new Promise((resolve) => setTimeout(resolve));

expect(get(myStore)).toBe('derived from initial');
expect(get(myState).isReloading).toBe(true);
Expand All @@ -1204,13 +1165,7 @@ describe('trackState', () => {
);
const { store: myStore, state: myState } = asyncDerived(
[parentA, parentB],
([$parentA, $parentB]) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`${$parentA} ${$parentB}`);
}, 100);
});
},
delayFunction(([$parentA, $parentB]) => `${$parentA} ${$parentB}`, 100),
{ trackState: true }
);

Expand All @@ -1224,7 +1179,6 @@ describe('trackState', () => {
expect(get(myState).isLoaded).toBe(true);

grandParent.set('updated');
await new Promise((resolve) => setTimeout(resolve));

expect(get(myStore)).toBe('initialA initialB');
expect(get(myState).isReloading).toBe(true);
Expand Down
17 changes: 17 additions & 0 deletions test/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
type FlatPromise<T> = T extends Promise<unknown> ? T : Promise<T>;

export const delayValue = <T>(value: T, delay = 0): FlatPromise<T> => {
return new Promise((resolve) =>
setTimeout(() => resolve(value), delay)
) as FlatPromise<T>;
};

export const delayFunction = <T, U>(
callback: (...args: T[]) => U,
delay = 0
): ((...args: T[]) => FlatPromise<U>) => {
return (...args: T[]) => {
const result = callback(...args);
return delayValue(result, delay);
};
};
1 change: 0 additions & 1 deletion test/standard-stores/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ describe('readable/writable stores', () => {
expect(stop).toHaveBeenCalledTimes(1);

await myReadable.load();
await new Promise((resolve) => setTimeout(resolve));
expect(stop).toHaveBeenCalledTimes(2);
});
});
Expand Down
3 changes: 2 additions & 1 deletion test/testing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('can be reset for different tests', () => {
});

it('loads rejection', async () => {
myReadable.subscribe(vi.fn());
const unsubscribe = myReadable.subscribe(vi.fn());
mockedFetch.mockRejectedValueOnce('rejected');
await myReadable.load().catch(() => Promise.resolve());

Expand All @@ -47,6 +47,7 @@ describe('can be reset for different tests', () => {
await myReadable.load().catch(() => Promise.resolve());

expect(get(myReadable)).toBe('initial');
unsubscribe();
});
});

Expand Down
Loading

0 comments on commit 28a6ea1

Please sign in to comment.