Files
upstream-affine/blocksuite/affine/ext-loader/src/__tests__/ext-loader.unit.spec.ts
upstream-mirror 702cc698a7
Some checks failed
Build & Test / Analyze (javascript, affine) (push) Failing after 4s
Build & Test / Analyze (typescript, affine) (push) Failing after 3s
Build & Test / Rust test filter (push) Failing after 4s
Build & Test / Check yarn binary (push) Failing after 3s
Build & Test / E2E BlockSuite Test (3) (push) Failing after 3s
Build & Test / Analyze (javascript, blocksuite) (push) Failing after 3s
Build & Test / Analyze (typescript, blocksuite) (push) Failing after 3s
Build & Test / Mobile native build filter (push) Failing after 3s
Build & Test / E2E BlockSuite Test (1) (push) Failing after 4s
Build & Test / E2E BlockSuite Test (2) (push) Failing after 4s
Build & Test / E2E Mobile Test (1) (push) Failing after 3s
Build & Test / Unit Test (1) (push) Has been skipped
Build & Test / Unit Test (2) (push) Has been skipped
Build & Test / Unit Test (3) (push) Has been skipped
Build & Test / Unit Test (4) (push) Has been skipped
Build & Test / Unit Test (5) (push) Has been skipped
Build & Test / Native Unit Test (push) Has been skipped
Build & Test / E2E BlockSuite Test (4) (push) Failing after 3s
Build & Test / E2E BlockSuite Test (5) (push) Failing after 3s
Build & Test / E2E BlockSuite Cross Browser Test (push) Failing after 3s
Build & Test / E2E Mobile Test (2) (push) Failing after 3s
Build & Test / Build AFFiNE native (x86_64-unknown-linux-gnu) (push) Failing after 3s
Build & Test / Build Server native (push) Failing after 3s
Build & Test / Check Git Status (push) Has been skipped
Build & Test / Server Test (0, 4) (push) Has been skipped
Build & Test / Server Test (1, 4) (push) Has been skipped
Build & Test / Server Test (2, 4) (push) Has been skipped
Build & Test / Server Test (3, 4) (push) Has been skipped
Build & Test / Server Test with Elasticsearch (push) Has been skipped
Build & Test / Build @affine/electron renderer (push) Failing after 3s
Build & Test / Copilot test filter (push) Failing after 4s
Build & Test / Lint Rust (push) Has been skipped
Build & Test / Server Test with Embedded Search (push) Has been skipped
Build & Test / Server Test with Manticore Search (push) Has been skipped
Build & Test / Server E2E Test (push) Has been skipped
Build & Test / Cloud Desktop E2E Test (push) Has been skipped
Build & Test / Cloud E2E Test 1/2 (push) Has been skipped
Build & Test / Cloud E2E Test 2/2 (push) Has been skipped
Build & Test / Build Android app (push) Has been skipped
Build & Test / Test Android app (push) Has been skipped
Build & Test / Run native tests (push) Has been skipped
Build & Test / Server Copilot Api Test (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (1, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (2, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (3, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (4, 5) (push) Has been skipped
Build & Test / Frontend Copilot E2E Test (5, 5) (push) Has been skipped
Release / Canary Gate (push) Has been skipped
Build & Test / Build AFFiNE native (aarch64-apple-darwin) (push) Has been cancelled
Build & Test / Lint (push) Has been cancelled
Build & Test / Typecheck (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-apple-darwin) (push) Has been cancelled
Build & Test / Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true) (push) Has been cancelled
Build & Test / Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true) (push) Has been cancelled
Build & Test / E2E Test (1) (push) Has been cancelled
Build & Test / E2E Test (2) (push) Has been cancelled
Build & Test / E2E Test (3) (push) Has been cancelled
Build & Test / E2E Test (4) (push) Has been cancelled
Build & Test / E2E Test (5) (push) Has been cancelled
Build & Test / Build AFFiNE native (aarch64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Build AFFiNE native (x86_64-pc-windows-msvc) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true) (push) Has been cancelled
Build & Test / Desktop Test (macos-latest, macos, x64, x86_64-apple-darwin, false) (push) Has been cancelled
Build & Test / 3, 2, 1 Launch (push) Has been cancelled
Build & Test / Build iOS app (push) Has been cancelled
Copilot Test Automatically / Setup Test (push) Failing after 1s
Release / Prepare (push) Failing after 2s
Release / Release Cloud (push) Has been skipped
Release / Release Desktop (push) Has been skipped
Release / Release Docker Image (push) Has been skipped
Release / Release Mobile (push) Has been skipped
snapshot of https://github.com/toeverything/AFFiNE.git (canary, 2026-09-16; blobs > 131072B omitted)
2026-09-16 04:01:20 +05:00

230 lines
5.8 KiB
TypeScript

import { Container } from '@blocksuite/global/di';
import { type ExtensionType } from '@blocksuite/store';
import { describe, expect, it, vi } from 'vitest';
import { z } from 'zod';
import { ExtensionManager } from '../manager';
import {
StoreExtensionManager,
StoreExtensionManagerIdentifier,
} from '../store-manager';
import {
type StoreExtensionContext,
StoreExtensionProvider,
} from '../store-provider';
import { ViewExtensionManager } from '../view-manager';
import {
type ViewExtensionContext,
ViewExtensionProvider,
} from '../view-provider';
export const Ext1: ExtensionType = {
setup: () => {},
};
export const Ext2: ExtensionType = {
setup: () => {},
};
export const Ext3: ExtensionType = {
setup: () => {},
};
export const Ext4: ExtensionType = {
setup: () => {},
};
export const Ext5: ExtensionType = {
setup: () => {},
};
it('should be able to load extensions', () => {
class StoreExt1 extends StoreExtensionProvider {
override name = 'StoreExt1';
override setup(context: StoreExtensionContext) {
super.setup(context);
context.register(Ext1);
}
}
const manager = new ExtensionManager([StoreExt1]);
const storeExtensions = manager.get('store');
expect(storeExtensions).toEqual([Ext1]);
});
describe('multiple scopes', () => {
const setup1 = vi.fn();
const setup2 = vi.fn();
class ViewExt1 extends ViewExtensionProvider {
override name = 'ViewExt1';
constructor() {
super();
setup1();
}
override setup(context: ViewExtensionContext, option?: { foo: number }) {
super.setup(context, option);
if (context.scope === 'page') {
context.register(Ext2);
}
if (context.scope === 'edgeless') {
context.register(Ext3);
}
}
}
class ViewExt2 extends ViewExtensionProvider {
override name = 'ViewExt2';
constructor() {
super();
setup2();
}
override setup(context: ViewExtensionContext) {
super.setup(context);
if (context.scope === 'page') {
context.register(Ext4);
}
if (context.scope === 'edgeless') {
context.register(Ext5);
}
}
}
const manager = new ExtensionManager([ViewExt1, ViewExt2]);
const pageExtensions = manager.get('page');
const edgelessExtensions = manager.get('edgeless');
it('should be able to load extensions from different scopes', () => {
expect(pageExtensions).toEqual([Ext2, Ext4]);
expect(edgelessExtensions).toEqual([Ext3, Ext5]);
});
it('should cache provider instances', () => {
manager.get('page');
manager.get('edgeless');
expect(setup1).toHaveBeenCalledTimes(1);
expect(setup2).toHaveBeenCalledTimes(1);
manager.get('page');
manager.get('edgeless');
expect(setup1).toHaveBeenCalledTimes(1);
expect(setup2).toHaveBeenCalledTimes(1);
});
});
it('should be able to validate schema', () => {
type Option = { foo: number; bar: string };
const setupOption = vi.fn();
class ViewExt1 extends ViewExtensionProvider<Option> {
override name = 'ViewExt1';
override schema = z.object({
foo: z.number(),
bar: z.string(),
});
override setup(context: ViewExtensionContext, option?: Option) {
super.setup(context, option);
if (context.scope === 'page') {
setupOption(option);
context.register(Ext1);
}
if (context.scope === 'edgeless') {
setupOption(option);
context.register(Ext2);
}
}
}
const manager = new ExtensionManager([ViewExt1]);
manager.configure(ViewExt1, { foo: 1, bar: '2' });
manager.configure(ViewExt1, prev => {
if (!prev) {
return prev;
}
return {
...prev,
foo: prev.foo + 1,
};
});
let viewExtensions = manager.get('page');
expect(viewExtensions).toEqual([Ext1]);
expect(setupOption).toHaveBeenCalledWith({ foo: 2, bar: '2' });
setupOption.mockClear();
manager.configure(ViewExt1, undefined);
viewExtensions = manager.get('edgeless');
expect(viewExtensions).toEqual([Ext2]);
expect(setupOption).toHaveBeenCalledWith(undefined);
viewExtensions = manager.get('page');
expect(setupOption).toHaveBeenCalledWith(undefined);
});
it('should extension manager be able to be injected', () => {
class StoreExt1 extends StoreExtensionProvider {
override name = 'StoreExt1';
override setup(context: StoreExtensionContext) {
super.setup(context);
context.register(Ext1);
}
}
const manager = new StoreExtensionManager([StoreExt1]);
const extensions = manager.get('store');
const container = new Container();
extensions.forEach(ext => {
ext.setup(container);
});
const provider = container.provider();
expect(provider.get(StoreExtensionManagerIdentifier)).toBe(manager);
});
it('should effect only run once', () => {
const effect1 = vi.fn();
const effect2 = vi.fn();
class ViewExt1 extends ViewExtensionProvider {
override name = 'ViewExt1';
override effect() {
super.effect();
effect1();
}
override setup(context: ViewExtensionContext) {
super.setup(context);
context.register(Ext1);
}
}
class ViewExt2 extends ViewExtensionProvider {
override name = 'ViewExt2';
override effect() {
super.effect();
effect2();
}
override setup(context: ViewExtensionContext) {
super.setup(context);
context.register(Ext2);
}
}
const manager = new ViewExtensionManager([ViewExt1]);
expect(ViewExt1.effectRan).toBe(false);
expect(ViewExt2.effectRan).toBe(false);
manager.get('page');
expect(ViewExt1.effectRan).toBe(true);
expect(ViewExt2.effectRan).toBe(false);
expect(effect1).toHaveBeenCalledTimes(1);
expect(effect2).toHaveBeenCalledTimes(0);
manager.get('edgeless');
expect(ViewExt1.effectRan).toBe(true);
expect(ViewExt2.effectRan).toBe(false);
expect(effect1).toHaveBeenCalledTimes(1);
expect(effect2).toHaveBeenCalledTimes(0);
});