Skip to content

Commit

Permalink
build(3.4.6): export isAtom isDerivedAtom
Browse files Browse the repository at this point in the history
  • Loading branch information
fantasticsoul committed Nov 29, 2023
1 parent 12463f6 commit 86b7a38
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 59 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "helux",
"version": "3.4.5",
"version": "3.4.6",
"description": "A state library core that integrates atom, signal, collection dep, derive and watch, it supports all react like frameworks( including react 18 ).",
"keywords": [],
"author": {
Expand Down
4 changes: 3 additions & 1 deletion packages/helux-core/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { limuUtils, produce } from 'limu';
import { EVENT_NAME, LOADING_MODE } from './consts/user';
import { getAtom } from './factory/common/atom';
import { getAtom, isAtom, isDerivedAtom } from './factory/common/atom';
import { addMiddleware } from './factory/common/middleware';
import { addPlugin } from './factory/common/plugin';
import { emit, on } from './factory/common/userBus';
Expand Down Expand Up @@ -77,6 +77,8 @@ export {
// util api
currentDraftRoot,
setAtomVal,
isAtom,
isDerivedAtom,
storeSrv,
produce,
shallowCompare,
Expand Down
2 changes: 1 addition & 1 deletion packages/helux-core/src/consts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSymbol, HAS_SYMBOL } from '../helpers/sym';
export { EVENT_NAME, FROM, LOADING_MODE } from './user';
export { HAS_SYMBOL };

export const VER = '3.4.5';
export const VER = '3.4.6';

export const PROD_FLAG = true;

Expand Down
4 changes: 2 additions & 2 deletions packages/helux-core/src/factory/common/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ export function checkShared<T = SharedState>(sharedState: T, options?: ICheckSha
// 传递了具体的 forAtom 布尔值,才严格校验是否是 atom 或 shared
if (forAtom !== undefined) {
if (forAtom && !internal.forAtom) {
tryAlert(`${prefix} expect for a shared but recived a atom`, true);
tryAlert(`${prefix} expect a shared but recived a atom`, true);
}
if (!forAtom && internal.forAtom) {
tryAlert(`${prefix} expect for a atom but recived a shared`, true);
tryAlert(`${prefix} expect a atom but recived a shared`, true);
}
}
return internal;
Expand Down
10 changes: 10 additions & 0 deletions packages/helux-core/src/types/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,16 @@ export function currentDraftRoot<T = any>(state?: T): T;
*/
export function setAtomVal<T = any>(val?: T): T;

/**
* test if the input arg is a result returned by atom()
*/
export function isAtom(mayAtom: any): boolean;

/**
* test if the input arg is a result returned by driveAtom()
*/
export function isDerivedAtom(mayDerivedAtom: any): boolean;

// ----------- shallowCompare isDiff produce 二次重导出会报错,这里手动声明一下 --------------
// err: 如果没有引用 "../../helux-core/node_modules/limu/lib",则无法命名 "produce" 的推断类型。这很可能不可移植。需要类型注释

Expand Down
2 changes: 1 addition & 1 deletion packages/helux/__tests__/atom/change.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ describe('change atom', () => {
expect(prevItem0 === currItem0).toBeFalsy();
// TODO: resolve this strange result problem
// browser console print ture but vitest console print false
// but 'true' is the expected result,what's wrong with vitest?
// and 'true' is the expected result,what's wrong with vitest?
// visit https://codesandbox.io/p/sandbox/strange-testcase-rl45wx?file=%2Fsrc%2FDemo.js ,
// open console to the log
// expect(prevItem1 === currItem1).toBeTruthy();
Expand Down
6 changes: 5 additions & 1 deletion packages/helux/__tests__/helux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { act } from '@testing-library/react';
import * as React from 'react';
import { initHeluxContext } from '../../helux-core/src/index';

// pass act to avlid Warning:
window.alert = () => {};

// pass act to avoid Warning:
// An update to TestComponent inside a test was not wrapped in act(...).
// This ensures that you're testing the behavior the user would see in the browser.
// Learn more at https://reactjs.org/link/wrap-tests-with-act
Expand Down Expand Up @@ -67,6 +69,8 @@ export const {
// util api
currentDraftRoot,
setAtomVal,
isAtom,
isDerivedAtom,
storeSrv,
shallowCompare,
isDiff,
Expand Down
158 changes: 106 additions & 52 deletions packages/helux/__tests__/hooks/useActionLoading.test.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,70 @@
import '@testing-library/jest-dom';
import { renderHook } from '@testing-library/react';
import { describe, expect, test } from 'vitest';
import { atom, atomActionAsync, useActionLoading, useAtom } from '../helux';
import { delay } from '../util';
import { actionAsync, atom, atomActionAsync, isAtom, share, useActionLoading, useAtom, useShared } from '../helux';
import { delay, noop } from '../util';

describe('useActionLoading', () => {
async function testLoading(numAtom, asyncAction, useActionLoading) {
const action1 = asyncAction(async ({ setState }) => {
await delay(100);
async function testLoading(state, asyncAction, useActionLoading) {
const action1 = asyncAction(async ({ setState }) => {
await delay(100);
if (isAtom(state)) {
setState(() => 100);
}, 'action1');

let runCount = 0;
const { result } = renderHook(() => {
runCount += 1;
const [ld] = useActionLoading();
return ld['action1'].loading;
});

expect(runCount).toBe(1);
expect(result.current).toBe(false);

await action1();
expect(numAtom.val).toBe(100);
// the new 2 render times: loading true ---> val=100 ---> loading false
expect(runCount).toBe(3);
}

async function testLoadingWithReadAtom(numAtom, asyncAction, useActionLoading) {
const action1 = asyncAction(async ({ setState }) => {
await delay(100);
setState(() => 100);
}, 'action1');
} else {
setState((draft) => (draft.val = 100));
}
}, 'action1');

let runCount = 0;
const { result } = renderHook(() => {
runCount += 1;
const [ld] = useActionLoading();
return ld['action1'].loading;
});

let runCount = 0;
const { result } = renderHook(() => {
runCount += 1;
useAtom(numAtom);
const [ld] = useActionLoading();
return ld['action1'].loading;
});
expect(runCount).toBe(1);
expect(result.current).toBe(false);

expect(runCount).toBe(1);
expect(result.current).toBe(false);
await action1();
expect(state.val).toBe(100);
// the new 2 render times: loading true ---> loading false
expect(runCount).toBe(3);
}

await action1();
expect(numAtom.val).toBe(100);
async function testLoadingWithUseStateHook(state, asyncAction, useActionLoading, useStateFn?: any) {
const useState = useStateFn || useAtom;
const action1 = asyncAction(async ({ setState }) => {
await delay(100);
if (isAtom(state)) {
setState(() => 100);
} else {
setState((draft) => (draft.val = 100));
}
}, 'action1');

let runCount = 0;
const { result } = renderHook(() => {
runCount += 1;
const [obj] = useState(state);
if (!isAtom(state)) {
noop(obj.val); // trigger read
}
const [ld] = useActionLoading();
return ld['action1'].loading;
});

// the new 3 render times: loading true ---> val=100 ---> loading false
expect(runCount).toBe(4);
expect(result.current).toBe(false);
}
expect(runCount).toBe(1);
expect(result.current).toBe(false);

test('ctx.asyncAction, ctx.useActionLoading', async () => {
await action1();
expect(state.val).toBe(100);

// the new 3 render times: loading true ---> val=100 ---> loading false
expect(runCount).toBe(4);
expect(result.current).toBe(false);
}

describe('atom useActionLoading', () => {
test('ctx.actionAsync, ctx.useActionLoading', async () => {
const [numAtom, , ctx] = atom(1);
await testLoading(numAtom, ctx.actionAsync, ctx.useActionLoading);
});
Expand All @@ -62,7 +74,7 @@ describe('useActionLoading', () => {
await testLoading(numAtom, atomActionAsync(numAtom), ctx.useActionLoading);
});

test('ctx.asyncAction, topApi.useActionLoading', async () => {
test('ctx.actionAsync, topApi.useActionLoading', async () => {
const [numAtom, , ctx] = atom(1);
await testLoading(numAtom, ctx.actionAsync, () => useActionLoading(numAtom));
});
Expand All @@ -72,23 +84,65 @@ describe('useActionLoading', () => {
await testLoading(numAtom, atomActionAsync(numAtom), () => useActionLoading(numAtom));
});

test('useAtom: ctx.asyncAction, ctx.useActionLoading', async () => {
test('useAtom: ctx.actionAsync, ctx.useActionLoading', async () => {
const [numAtom, , ctx] = atom(1);
await testLoadingWithReadAtom(numAtom, ctx.actionAsync, ctx.useActionLoading);
await testLoadingWithUseStateHook(numAtom, ctx.actionAsync, ctx.useActionLoading);
});

test('useAtom: topApi.asyncAction, ctx.useActionLoading', async () => {
const [numAtom, , ctx] = atom(1);
await testLoadingWithReadAtom(numAtom, atomActionAsync(numAtom), ctx.useActionLoading);
await testLoadingWithUseStateHook(numAtom, atomActionAsync(numAtom), ctx.useActionLoading);
});

test('useAtom: ctx.asyncAction, topApi.useActionLoading', async () => {
test('useAtom: ctx.actionAsync, topApi.useActionLoading', async () => {
const [numAtom, , ctx] = atom(1);
await testLoadingWithReadAtom(numAtom, ctx.actionAsync, () => useActionLoading(numAtom));
await testLoadingWithUseStateHook(numAtom, ctx.actionAsync, () => useActionLoading(numAtom));
});

test('useAtom: topApi.asyncAction, topApi.useActionLoading', async () => {
const [numAtom] = atom(1);
await testLoadingWithReadAtom(numAtom, atomActionAsync(numAtom), () => useActionLoading(numAtom));
await testLoadingWithUseStateHook(numAtom, atomActionAsync(numAtom), () => useActionLoading(numAtom));
});
});

describe('share useActionLoading', () => {
test('ctx.actionAsync, ctx.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoading(state, ctx.actionAsync, ctx.useActionLoading);
});

test('topApi.asyncAction, ctx.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoading(state, actionAsync(state), ctx.useActionLoading);
});

test('ctx.actionAsync, topApi.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoading(state, ctx.actionAsync, () => useActionLoading(state));
});

test('topApi.asyncAction, topApi.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoading(state, actionAsync(state), () => useActionLoading(state));
});

test('useShared: ctx.actionAsync, ctx.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoadingWithUseStateHook(state, ctx.actionAsync, ctx.useActionLoading, useShared);
});

test('useShared: topApi.asyncAction, ctx.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoadingWithUseStateHook(state, actionAsync(state), ctx.useActionLoading, useShared);
});

test('useShared: ctx.actionAsync, topApi.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoadingWithUseStateHook(state, ctx.actionAsync, () => useActionLoading(state), useShared);
});

test('useShared: topApi.asyncAction, topApi.useActionLoading', async () => {
const [state, , ctx] = share({ val: 1 });
await testLoadingWithUseStateHook(state, actionAsync(state), () => useActionLoading(state), useShared);
});
});
4 changes: 4 additions & 0 deletions packages/helux/__tests__/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export function delay(ms = 1000) {
return new Promise((r) => setTimeout(r, ms));
}

export function noop(...args: any[]) {
return args;
}

/**
* for getting pretty format multi line string when use \`...\`
* this function will remove indent of every line automatically
Expand Down
2 changes: 2 additions & 0 deletions packages/helux/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export const {
// util api
currentDraftRoot,
setAtomVal,
isAtom,
isDerivedAtom,
storeSrv,
shallowCompare,
isDiff,
Expand Down

0 comments on commit 86b7a38

Please sign in to comment.