refactor!: next generation AFFiNE code structure (#1176)

This commit is contained in:
Himself65
2023-03-01 01:40:01 -06:00
committed by GitHub
parent 2dcccc772c
commit e0481d29ad
270 changed files with 8308 additions and 6829 deletions
@@ -0,0 +1,17 @@
// Vitest Snapshot v1
exports[`usePageMetas > basic 1`] = `
<DocumentFragment>
<div>
<div>
page0
</div>
<div>
page1
</div>
<div>
page2
</div>
</div>
</DocumentFragment>
`;
+180
View File
@@ -0,0 +1,180 @@
/**
* @vitest-environment happy-dom
*/
import 'fake-indexeddb/auto';
import assert from 'node:assert';
import { __unstableSchemas, builtInSchemas } from '@blocksuite/blocks/models';
import { assertExists } from '@blocksuite/store';
import { render, renderHook } from '@testing-library/react';
import { useRouter } from 'next/router';
import routerMock from 'next-router-mock';
import { createDynamicRouteParser } from 'next-router-mock/dynamic-routes';
import { beforeAll, beforeEach, describe, expect, test } from 'vitest';
import { BlockSuiteWorkspace, RemWorkspaceFlavour } from '../../shared';
import { useCurrentWorkspace } from '../current/use-current-workspace';
import { useLastOpenedWorkspace } from '../use-last-opened-workspace';
import { usePageMeta, usePageMetaHelper } from '../use-page-meta';
import { useSyncRouterWithCurrentWorkspaceAndPage } from '../use-sync-router-with-current-workspace-and-page';
import {
useWorkspaces,
useWorkspacesHelper,
vitestRefreshWorkspaces,
} from '../use-workspaces';
let blockSuiteWorkspace: BlockSuiteWorkspace;
beforeAll(() => {
routerMock.useParser(
createDynamicRouteParser(['/workspace/[workspaceId]/[pageId]'])
);
});
beforeEach(async () => {
vitestRefreshWorkspaces();
dataCenter.isLoaded = true;
return new Promise<void>(resolve => {
blockSuiteWorkspace = new BlockSuiteWorkspace({
room: 'test',
})
.register(builtInSchemas)
.register(__unstableSchemas);
blockSuiteWorkspace.signals.pageAdded.on(pageId => {
setTimeout(() => {
const page = blockSuiteWorkspace.getPage(pageId);
expect(page).not.toBeNull();
assertExists(page);
const pageBlockId = page.addBlockByFlavour('affine:page', {
title: '',
});
const frameId = page.addBlockByFlavour('affine:frame', {}, pageBlockId);
page.addBlockByFlavour('affine:paragraph', {}, frameId);
if (pageId === 'page2') {
resolve();
}
});
});
blockSuiteWorkspace.createPage('page0');
blockSuiteWorkspace.createPage('page1');
blockSuiteWorkspace.createPage('page2');
});
});
describe('usePageMetas', async () => {
test('basic', async () => {
const Component = () => {
const pageMetas = usePageMeta(blockSuiteWorkspace);
return (
<div>
{pageMetas.map(meta => (
<div key={meta.id}>{meta.id}</div>
))}
</div>
);
};
const result = render(<Component />);
await result.findByText('page0');
await result.findByText('page1');
await result.findByText('page2');
expect(result.asFragment()).toMatchSnapshot();
});
test('mutation', () => {
const { result, rerender } = renderHook(() =>
usePageMeta(blockSuiteWorkspace)
);
expect(result.current.length).toBe(3);
expect(result.current[0].mode).not.exist;
const { result: result2 } = renderHook(() =>
usePageMetaHelper(blockSuiteWorkspace)
);
result2.current.setPageMeta('page0', {
mode: 'edgeless',
});
rerender();
expect(result.current[0].mode).exist;
expect(result.current[0].mode).toBe('edgeless');
result2.current.setPageMeta('page0', {
mode: 'page',
});
rerender();
expect(result.current[0].mode).toBe('page');
});
});
describe('useWorkspaces', () => {
test('basic', () => {
const { result } = renderHook(() => useWorkspaces());
expect(result.current).toEqual([]);
});
test('mutation', () => {
const { result } = renderHook(() => useWorkspacesHelper());
result.current.createRemLocalWorkspace('test');
const { result: result2 } = renderHook(() => useWorkspaces());
expect(result2.current.length).toEqual(1);
const firstWorkspace = result2.current[0];
expect(firstWorkspace.flavour).toBe('local');
assert(firstWorkspace.flavour === RemWorkspaceFlavour.LOCAL);
expect(firstWorkspace.blockSuiteWorkspace.meta.name).toBe('test');
});
});
describe('useSyncRouterWithCurrentWorkspaceAndPage', () => {
test('from "/"', async () => {
const mutationHook = renderHook(() => useWorkspacesHelper());
const id = mutationHook.result.current.createRemLocalWorkspace('test0');
mutationHook.result.current.createWorkspacePage(id, 'page0');
const routerHook = renderHook(() => useRouter());
await routerHook.result.current.push('/');
routerHook.rerender();
expect(routerHook.result.current.asPath).toBe('/');
renderHook(
({ router }) => useSyncRouterWithCurrentWorkspaceAndPage(router),
{
initialProps: {
router: routerHook.result.current,
},
}
);
expect(routerHook.result.current.asPath).toBe(`/workspace/${id}/page0`);
});
test('from incorrect "/workspace/[workspaceId]/[pageId]"', async () => {
const mutationHook = renderHook(() => useWorkspacesHelper());
const id = mutationHook.result.current.createRemLocalWorkspace('test0');
mutationHook.result.current.createWorkspacePage(id, 'page0');
const routerHook = renderHook(() => useRouter());
await routerHook.result.current.push(`/workspace/${id}/not_exist`);
routerHook.rerender();
expect(routerHook.result.current.asPath).toBe(`/workspace/${id}/not_exist`);
renderHook(
({ router }) => useSyncRouterWithCurrentWorkspaceAndPage(router),
{
initialProps: {
router: routerHook.result.current,
},
}
);
expect(routerHook.result.current.asPath).toBe(`/workspace/${id}/page0`);
});
});
describe('useLastOpenedWorkspace', () => {
test('basic', async () => {
const workspaceHelperHook = renderHook(() => useWorkspacesHelper());
workspaceHelperHook.result.current.createRemLocalWorkspace('test');
const workspacesHook = renderHook(() => useWorkspaces());
const currentWorkspaceHook = renderHook(() => useCurrentWorkspace());
currentWorkspaceHook.result.current[1](workspacesHook.result.current[0].id);
const lastOpenedWorkspace = renderHook(() => useLastOpenedWorkspace());
expect(lastOpenedWorkspace.result.current[0]).toBe(null);
const lastOpenedWorkspace2 = renderHook(() => useLastOpenedWorkspace());
expect(lastOpenedWorkspace2.result.current[0]).toBe(
workspacesHook.result.current[0].id
);
});
});
@@ -0,0 +1,53 @@
/**
* @vitest-environment happy-dom
*/
import 'fake-indexeddb/auto';
import { __unstableSchemas, builtInSchemas } from '@blocksuite/blocks/models';
import { Page } from '@blocksuite/store';
import { renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, test, vi } from 'vitest';
import { BlockSuiteWorkspace } from '../../shared';
import { useBlockSuiteWorkspaceHelper } from '../use-blocksuite-workspace-helper';
import { usePageMeta } from '../use-page-meta';
import { vitestRefreshWorkspaces } from '../use-workspaces';
let blockSuiteWorkspace: BlockSuiteWorkspace;
beforeEach(() => {
vitestRefreshWorkspaces();
blockSuiteWorkspace = new BlockSuiteWorkspace({
room: 'test',
})
.register(builtInSchemas)
.register(__unstableSchemas);
blockSuiteWorkspace.signals.pageAdded.on(pageId => {
const page = blockSuiteWorkspace.getPage(pageId) as Page;
const pageBlockId = page.addBlockByFlavour('affine:page', { title: '' });
const frameId = page.addBlockByFlavour('affine:frame', {}, pageBlockId);
page.addBlockByFlavour('affine:paragraph', {}, frameId);
});
blockSuiteWorkspace.createPage('page0');
blockSuiteWorkspace.createPage('page1');
blockSuiteWorkspace.createPage('page2');
});
describe('useBlockSuiteWorkspaceHelper', () => {
test('should create page', () => {
expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3);
const helperHook = renderHook(() =>
useBlockSuiteWorkspaceHelper(blockSuiteWorkspace)
);
const pageMetaHook = renderHook(() => usePageMeta(blockSuiteWorkspace));
expect(pageMetaHook.result.current.length).toBe(3);
expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3);
const callback = vi.fn(id => {
expect(id).toBe('page4');
});
helperHook.result.current.createPage('page4').then(callback);
expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(4);
pageMetaHook.rerender();
expect(pageMetaHook.result.current.length).toBe(4);
});
});
@@ -0,0 +1,25 @@
/**
* @vitest-environment happy-dom
*/
import { renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, test } from 'vitest';
import { defaultRecord, useFeatureFlag } from '../use-feature-flag';
beforeEach(() => {
globalThis.featureFlag.record = defaultRecord;
globalThis.featureFlag.callback.clear();
});
describe('useFeatureFlag', () => {
test('basic', () => {
const flagHook = renderHook(() =>
useFeatureFlag('enableIndexedDBProvider')
);
expect(flagHook.result.current).toBe(defaultRecord.enableIndexedDBProvider);
globalThis.featureFlag.record.enableIndexedDBProvider = false;
globalThis.featureFlag.callback.forEach(cb => cb());
flagHook.rerender();
expect(flagHook.result.current).toBe(false);
});
});
@@ -0,0 +1,101 @@
/**
* @vitest-environment happy-dom
*/
import { renderHook } from '@testing-library/react';
import { useRouter } from 'next/router';
import routerMock from 'next-router-mock';
import { createDynamicRouteParser } from 'next-router-mock/dynamic-routes';
import { beforeAll, describe, expect, test } from 'vitest';
import { WorkspaceSubPath } from '../../shared';
import { RouteLogic, useRouterHelper } from '../use-router-helper';
beforeAll(() => {
routerMock.useParser(
createDynamicRouteParser([
'/workspace/[workspaceId]/[pageId]',
'/workspace/[workspaceId]/all',
'/workspace/[workspaceId]/favorite',
'/workspace/[workspaceId]/trash',
'/workspace/[workspaceId]/setting',
])
);
});
describe('useRouterHelper', () => {
test('should return a expected router helper', async () => {
const routerHook = renderHook(() => useRouter());
const helperHook = renderHook(router => useRouterHelper(router), {
initialProps: routerHook.result.current,
});
const hook = helperHook.result.current;
expect(hook).toBeTypeOf('object');
Object.values(hook).forEach(value => {
expect(value).toBeTypeOf('function');
});
});
test('should jump to the expected sub path', async () => {
const routerHook = renderHook(() => useRouter());
// set current path to '/'
await routerHook.result.current.replace('/');
const helperHook = renderHook(router => useRouterHelper(router), {
initialProps: routerHook.result.current,
});
const hook = helperHook.result.current;
await hook.jumpToSubPath('workspace0', WorkspaceSubPath.ALL);
routerHook.rerender();
expect(routerHook.result.current.pathname).toBe(
'/workspace/[workspaceId]/all'
);
expect(routerHook.result.current.asPath).toBe('/workspace/workspace0/all');
// `router.back` is not working in `next-router-mock`
// routerHook.result.current.back()
// routerHook.rerender()
// expect(routerHook.result.current.pathname).toBe('/')
await hook.jumpToSubPath(
'workspace1',
WorkspaceSubPath.FAVORITE,
RouteLogic.REPLACE
);
routerHook.rerender();
expect(routerHook.result.current.pathname).toBe(
'/workspace/[workspaceId]/favorite'
);
expect(routerHook.result.current.asPath).toBe(
'/workspace/workspace1/favorite'
);
});
test('should jump to the expected page', async () => {
const routerHook = renderHook(() => useRouter());
// set current path to '/'
await routerHook.result.current.replace('/');
const helperHook = renderHook(router => useRouterHelper(router), {
initialProps: routerHook.result.current,
});
const hook = helperHook.result.current;
await hook.jumpToPage('workspace0', 'page0');
routerHook.rerender();
expect(routerHook.result.current.pathname).toBe(
'/workspace/[workspaceId]/[pageId]'
);
expect(routerHook.result.current.asPath).toBe(
'/workspace/workspace0/page0'
);
// `router.back` is not working in `next-router-mock`
// routerHook.result.current.back()
// routerHook.rerender()
// expect(routerHook.result.current.pathname).toBe('/')
await hook.jumpToPage('workspace1', 'page1', RouteLogic.REPLACE);
routerHook.rerender();
expect(routerHook.result.current.pathname).toBe(
'/workspace/[workspaceId]/[pageId]'
);
expect(routerHook.result.current.asPath).toBe(
'/workspace/workspace1/page1'
);
});
});
@@ -0,0 +1,23 @@
/**
* @vitest-environment happy-dom
*/
import { renderHook } from '@testing-library/react';
import { describe, expect, test, vi } from 'vitest';
import { useSystemOnline } from '../use-system-online';
describe('useSystemOnline', () => {
test('should be online', () => {
const systemOnlineHook = renderHook(() => useSystemOnline());
expect(systemOnlineHook.result.current).toBe(true);
});
test('should be offline', () => {
const systemOnlineHook = renderHook(() => useSystemOnline());
vi.spyOn(navigator, 'onLine', 'get').mockReturnValue(false);
expect(systemOnlineHook.result.current).toBe(true);
window.dispatchEvent(new Event('offline'));
systemOnlineHook.rerender();
expect(systemOnlineHook.result.current).toBe(false);
});
});