wip
This commit is contained in:
@@ -39,8 +39,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
}
|
||||
throw reason;
|
||||
};
|
||||
const anyProcess = process as any;
|
||||
anyProcess.on('unhandledRejection', unhandledRejectionHandler);
|
||||
process.on('unhandledRejection', unhandledRejectionHandler);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -54,8 +53,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
|
||||
afterAll(() => {
|
||||
if (unhandledRejectionHandler) {
|
||||
const anyProcess = process as any;
|
||||
anyProcess.removeListener('unhandledRejection', unhandledRejectionHandler);
|
||||
process.removeListener('unhandledRejection', unhandledRejectionHandler);
|
||||
unhandledRejectionHandler = null;
|
||||
}
|
||||
});
|
||||
@@ -177,12 +175,19 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
it('should log browser mode configuration with NODE_ENV source in production', async () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const logSpy: Array<{ level: string; message: string; context?: any }> = [];
|
||||
const mockLogger = {
|
||||
debug: (msg: string, ctx?: any) => logSpy.push({ level: 'debug', message: msg, context: ctx }),
|
||||
info: (msg: string, ctx?: any) => logSpy.push({ level: 'info', message: msg, context: ctx }),
|
||||
warn: (msg: string, ctx?: any) => logSpy.push({ level: 'warn', message: msg, context: ctx }),
|
||||
error: (msg: string, ctx?: any) => logSpy.push({ level: 'error', message: msg, context: ctx }),
|
||||
const logSpy: Array<{ level: string; message: string; context?: Record<string, unknown> }> = [];
|
||||
type LoggerLike = {
|
||||
debug: (msg: string, ctx?: Record<string, unknown>) => void;
|
||||
info: (msg: string, ctx?: Record<string, unknown>) => void;
|
||||
warn: (msg: string, ctx?: Record<string, unknown>) => void;
|
||||
error: (msg: string, ctx?: Record<string, unknown>) => void;
|
||||
child: () => LoggerLike;
|
||||
};
|
||||
const mockLogger: LoggerLike = {
|
||||
debug: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'debug', message: msg, context: ctx }),
|
||||
info: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'info', message: msg, context: ctx }),
|
||||
warn: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'warn', message: msg, context: ctx }),
|
||||
error: (msg: string, ctx?: Record<string, unknown>) => logSpy.push({ level: 'error', message: msg, context: ctx }),
|
||||
child: () => mockLogger,
|
||||
};
|
||||
|
||||
@@ -192,7 +197,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
|
||||
adapter = new PlaywrightAutomationAdapter(
|
||||
{ mode: 'mock' },
|
||||
mockLogger as any
|
||||
mockLogger
|
||||
);
|
||||
|
||||
await adapter.connect();
|
||||
@@ -250,19 +255,23 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
loader.setDevelopmentMode('headed');
|
||||
|
||||
// Capture launch options
|
||||
const launches: Array<{ type: string; opts?: any; userDataDir?: string }> = [];
|
||||
type LaunchOptions = { headless?: boolean; [key: string]: unknown };
|
||||
const launches: Array<{ type: string; opts?: LaunchOptions; userDataDir?: string }> = [];
|
||||
|
||||
const mockLauncher = {
|
||||
launch: async (opts: any) => {
|
||||
launch: async (opts: LaunchOptions) => {
|
||||
launches.push({ type: 'launch', opts });
|
||||
return {
|
||||
newContext: async () => ({ newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }), close: async () => {} }),
|
||||
newContext: async () => ({
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
newContextSync: () => {},
|
||||
};
|
||||
},
|
||||
launchPersistentContext: async (userDataDir: string, opts: any) => {
|
||||
launchPersistentContext: async (userDataDir: string, opts: LaunchOptions) => {
|
||||
launches.push({ type: 'launchPersistent', userDataDir, opts });
|
||||
return {
|
||||
pages: () => [{ setDefaultTimeout: () => {}, close: async () => {} }],
|
||||
@@ -273,9 +282,12 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
};
|
||||
|
||||
// Inject test launcher
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = mockLauncher;
|
||||
const AdapterWithTestLauncher = PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: typeof mockLauncher;
|
||||
};
|
||||
AdapterWithTestLauncher.testLauncher = mockLauncher;
|
||||
|
||||
adapter = new PlaywrightAutomationAdapter({ mode: 'mock' }, undefined as any, loader as any);
|
||||
adapter = new PlaywrightAutomationAdapter({ mode: 'mock' }, undefined, loader);
|
||||
|
||||
// First connect => loader says headed => headless should be false
|
||||
const r1 = await adapter.connect();
|
||||
@@ -296,7 +308,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
|
||||
expect(secondLaunch!.opts.headless).toBe(true);
|
||||
|
||||
// Cleanup test hook
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = undefined;
|
||||
AdapterWithTestLauncher.testLauncher = undefined;
|
||||
await adapter.disconnect();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,12 +3,14 @@ import { PlaywrightAutomationAdapter } from 'packages/automation/infrastructure/
|
||||
|
||||
describe('CarsFlow integration', () => {
|
||||
test('adapter emits panel-attached then action-started then action-complete for performAddCar', async () => {
|
||||
const adapter = new PlaywrightAutomationAdapter({} as any)
|
||||
const received: any[] = []
|
||||
adapter.onLifecycle?.((e: any) => { received.push(e) })
|
||||
|
||||
const adapter = new PlaywrightAutomationAdapter({})
|
||||
const received: Array<{ type: string }> = []
|
||||
adapter.onLifecycle?.((e) => {
|
||||
received.push({ type: (e as { type: string }).type })
|
||||
})
|
||||
|
||||
// Use mock page fixture: minimal object with required methods
|
||||
const mockPage: any = {
|
||||
const mockPage = {
|
||||
waitForSelector: async () => {},
|
||||
evaluate: async () => {},
|
||||
waitForTimeout: async () => {},
|
||||
@@ -20,11 +22,13 @@ describe('CarsFlow integration', () => {
|
||||
await adapter.attachPanel(mockPage, 'add-car')
|
||||
|
||||
// simulate complete event via internal lifecycle emitter
|
||||
await (adapter as any).emitLifecycle({
|
||||
type: 'action-complete',
|
||||
actionId: 'add-car',
|
||||
timestamp: Date.now(),
|
||||
} as any)
|
||||
await (adapter as unknown as { emitLifecycle: (ev: { type: string; actionId: string; timestamp: number }) => Promise<void> }).emitLifecycle(
|
||||
{
|
||||
type: 'action-complete',
|
||||
actionId: 'add-car',
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
)
|
||||
|
||||
const types = received.map(r => r.type)
|
||||
expect(types.indexOf('panel-attached')).toBeGreaterThanOrEqual(0)
|
||||
|
||||
@@ -40,7 +40,13 @@ describe('Overlay lifecycle (integration)', () => {
|
||||
it('emits modal-opened and confirms after action-started in sane order', async () => {
|
||||
const lifecycleEmitter = new TestLifecycleEmitter();
|
||||
const publisher = new RecordingPublisher();
|
||||
const logger = console as any;
|
||||
type LoggerLike = {
|
||||
debug: (...args: unknown[]) => void;
|
||||
info: (...args: unknown[]) => void;
|
||||
warn: (...args: unknown[]) => void;
|
||||
error: (...args: unknown[]) => void;
|
||||
};
|
||||
const logger = console as unknown as LoggerLike;
|
||||
|
||||
const service = new OverlaySyncService({
|
||||
lifecycleEmitter,
|
||||
@@ -85,7 +91,13 @@ describe('Overlay lifecycle (integration)', () => {
|
||||
it('emits panel-missing when cancelAction is called', async () => {
|
||||
const lifecycleEmitter = new TestLifecycleEmitter();
|
||||
const publisher = new RecordingPublisher();
|
||||
const logger = console as any;
|
||||
type LoggerLike = {
|
||||
debug: (...args: unknown[]) => void;
|
||||
info: (...args: unknown[]) => void;
|
||||
warn: (...args: unknown[]) => void;
|
||||
error: (...args: unknown[]) => void;
|
||||
};
|
||||
const logger = console as unknown as LoggerLike;
|
||||
|
||||
const service = new OverlaySyncService({
|
||||
lifecycleEmitter,
|
||||
|
||||
@@ -10,11 +10,13 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'development' };
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as any).testLauncher;
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: unknown;
|
||||
}).testLauncher;
|
||||
|
||||
const mockLauncher = {
|
||||
launch: async (_opts: any) => ({
|
||||
launch: async (_opts: unknown) => ({
|
||||
newContext: async () => ({
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
@@ -22,14 +24,16 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
launchPersistentContext: async (_userDataDir: string, _opts: any) => ({
|
||||
launchPersistentContext: async (_userDataDir: string, _opts: unknown) => ({
|
||||
pages: () => [{ setDefaultTimeout: () => {}, close: async () => {} }],
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
};
|
||||
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = mockLauncher;
|
||||
(PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: typeof mockLauncher;
|
||||
}).testLauncher = mockLauncher;
|
||||
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
@@ -38,7 +42,9 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = originalTestLauncher;
|
||||
(PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: unknown;
|
||||
}).testLauncher = originalTestLauncher;
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
@@ -49,8 +55,8 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
expect(loader.getDevelopmentMode()).toBe('headed');
|
||||
|
||||
const preStart = container.getStartAutomationUseCase();
|
||||
const preEngine: any = container.getAutomationEngine();
|
||||
const preAutomation = container.getBrowserAutomation() as any;
|
||||
const preEngine = container.getAutomationEngine();
|
||||
const preAutomation = container.getBrowserAutomation();
|
||||
|
||||
expect(preAutomation).toBe(preEngine.browserAutomation);
|
||||
|
||||
@@ -58,8 +64,8 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
container.refreshBrowserAutomation();
|
||||
|
||||
const postStart = container.getStartAutomationUseCase();
|
||||
const postEngine: any = container.getAutomationEngine();
|
||||
const postAutomation = container.getBrowserAutomation() as any;
|
||||
const postEngine = container.getAutomationEngine();
|
||||
const postAutomation = container.getBrowserAutomation();
|
||||
|
||||
expect(postAutomation).toBe(postEngine.browserAutomation);
|
||||
expect(postAutomation).not.toBe(preAutomation);
|
||||
@@ -78,7 +84,7 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
|
||||
await postEngine.executeStep(StepId.create(1), config);
|
||||
|
||||
const sessionRepository: any = container.getSessionRepository();
|
||||
const sessionRepository = container.getSessionRepository();
|
||||
const session = await sessionRepository.findById(dto.sessionId);
|
||||
|
||||
expect(session).toBeDefined();
|
||||
@@ -90,8 +96,9 @@ describe('companion start automation - browser mode refresh wiring', () => {
|
||||
expect(errorMessage).not.toContain('Browser not connected');
|
||||
}
|
||||
|
||||
const automationFromConnection = container.getBrowserAutomation() as any;
|
||||
const automationFromEngine = (container.getAutomationEngine() as any).browserAutomation;
|
||||
const automationFromConnection = container.getBrowserAutomation();
|
||||
const automationFromEngine = (container.getAutomationEngine() as { browserAutomation: unknown })
|
||||
.browserAutomation;
|
||||
|
||||
expect(automationFromConnection).toBe(automationFromEngine);
|
||||
expect(automationFromConnection).toBe(postAutomation);
|
||||
|
||||
@@ -10,11 +10,13 @@ describe('companion start automation - browser not connected at step 1', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'production' };
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as any).testLauncher;
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: unknown;
|
||||
}).testLauncher;
|
||||
|
||||
const mockLauncher = {
|
||||
launch: async (_opts: any) => ({
|
||||
launch: async (_opts: unknown) => ({
|
||||
newContext: async () => ({
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
@@ -22,14 +24,16 @@ describe('companion start automation - browser not connected at step 1', () => {
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
launchPersistentContext: async (_userDataDir: string, _opts: any) => ({
|
||||
launchPersistentContext: async (_userDataDir: string, _opts: unknown) => ({
|
||||
pages: () => [{ setDefaultTimeout: () => {}, close: async () => {} }],
|
||||
newPage: async () => ({ setDefaultTimeout: () => {}, close: async () => {} }),
|
||||
close: async () => {},
|
||||
}),
|
||||
};
|
||||
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = mockLauncher;
|
||||
(PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: typeof mockLauncher;
|
||||
}).testLauncher = mockLauncher;
|
||||
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
@@ -38,22 +42,24 @@ describe('companion start automation - browser not connected at step 1', () => {
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = originalTestLauncher;
|
||||
(PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: unknown;
|
||||
}).testLauncher = originalTestLauncher;
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('marks the session as FAILED with Step 1 (LOGIN) browser-not-connected error', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const startAutomationUseCase = container.getStartAutomationUseCase();
|
||||
const sessionRepository: any = container.getSessionRepository();
|
||||
const sessionRepository = container.getSessionRepository();
|
||||
const automationEngine = container.getAutomationEngine();
|
||||
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(true);
|
||||
|
||||
const browserAutomation = container.getBrowserAutomation() as any;
|
||||
if (browserAutomation.disconnect) {
|
||||
await browserAutomation.disconnect();
|
||||
const browserAutomation = container.getBrowserAutomation();
|
||||
if (typeof (browserAutomation as { disconnect?: () => Promise<void> }).disconnect === 'function') {
|
||||
await (browserAutomation as { disconnect: () => Promise<void> }).disconnect();
|
||||
}
|
||||
|
||||
const config: HostedSessionConfig = {
|
||||
@@ -77,10 +83,10 @@ describe('companion start automation - browser not connected at step 1', () => {
|
||||
});
|
||||
|
||||
async function waitForFailedSession(
|
||||
sessionRepository: { findById: (id: string) => Promise<any> },
|
||||
sessionRepository: { findById: (id: string) => Promise<{ state?: { value?: string }; errorMessage?: unknown } | null> },
|
||||
sessionId: string,
|
||||
timeoutMs = 5000,
|
||||
): Promise<any> {
|
||||
): Promise<{ state?: { value?: string }; errorMessage?: unknown } | null> {
|
||||
const start = Date.now();
|
||||
let last: any = null;
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@ describe('companion start automation - browser connection failure before steps',
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv, NODE_ENV: 'production' };
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as any).testLauncher;
|
||||
|
||||
originalTestLauncher = (PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: unknown;
|
||||
}).testLauncher;
|
||||
|
||||
const failingLauncher = {
|
||||
launch: async () => {
|
||||
@@ -21,7 +23,9 @@ describe('companion start automation - browser connection failure before steps',
|
||||
},
|
||||
};
|
||||
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = failingLauncher;
|
||||
(PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: typeof failingLauncher;
|
||||
}).testLauncher = failingLauncher;
|
||||
|
||||
DIContainer.resetInstance();
|
||||
});
|
||||
@@ -30,21 +34,26 @@ describe('companion start automation - browser connection failure before steps',
|
||||
const container = DIContainer.getInstance();
|
||||
await container.shutdown();
|
||||
DIContainer.resetInstance();
|
||||
(PlaywrightAutomationAdapter as any).testLauncher = originalTestLauncher;
|
||||
(PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
testLauncher?: unknown;
|
||||
}).testLauncher = originalTestLauncher;
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it('fails browser connection and aborts before executing step 1', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const startAutomationUseCase = container.getStartAutomationUseCase();
|
||||
const sessionRepository: any = container.getSessionRepository();
|
||||
const sessionRepository = container.getSessionRepository();
|
||||
const automationEngine = container.getAutomationEngine();
|
||||
|
||||
const connectionResult = await container.initializeBrowserConnection();
|
||||
expect(connectionResult.success).toBe(false);
|
||||
expect(connectionResult.error).toBeDefined();
|
||||
|
||||
const executeStepSpy = vi.spyOn(automationEngine, 'executeStep' as any);
|
||||
const executeStepSpy = vi.spyOn(
|
||||
automationEngine,
|
||||
'executeStep' as keyof typeof automationEngine,
|
||||
);
|
||||
|
||||
const config: HostedSessionConfig = {
|
||||
sessionName: 'Companion integration connection failure',
|
||||
@@ -78,12 +87,17 @@ describe('companion start automation - browser connection failure before steps',
|
||||
it('treats successful adapter connect without a page as connection failure', async () => {
|
||||
const container = DIContainer.getInstance();
|
||||
const browserAutomation = container.getBrowserAutomation();
|
||||
|
||||
|
||||
expect(browserAutomation).toBeInstanceOf(PlaywrightAutomationAdapter);
|
||||
|
||||
const originalConnect = (PlaywrightAutomationAdapter as any).prototype.connect;
|
||||
|
||||
(PlaywrightAutomationAdapter as any).prototype.connect = async function () {
|
||||
|
||||
const AdapterWithPrototype = PlaywrightAutomationAdapter as typeof PlaywrightAutomationAdapter & {
|
||||
prototype: {
|
||||
connect: () => Promise<{ success: boolean; error?: string }>;
|
||||
};
|
||||
};
|
||||
const originalConnect = AdapterWithPrototype.prototype.connect;
|
||||
|
||||
AdapterWithPrototype.prototype.connect = async function () {
|
||||
return { success: true };
|
||||
};
|
||||
|
||||
@@ -93,7 +107,7 @@ describe('companion start automation - browser connection failure before steps',
|
||||
expect(connectionResult.error).toBeDefined();
|
||||
expect(String(connectionResult.error).toLowerCase()).toContain('browser');
|
||||
} finally {
|
||||
(PlaywrightAutomationAdapter as any).prototype.connect = originalConnect;
|
||||
AdapterWithPrototype.prototype.connect = originalConnect;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -49,9 +49,9 @@ describe('renderer overlay lifecycle integration', () => {
|
||||
const emitter = new MockAutomationLifecycleEmitter();
|
||||
const publisher = new RecordingPublisher();
|
||||
const svc = new OverlaySyncService({
|
||||
lifecycleEmitter: emitter as any,
|
||||
publisher: publisher as any,
|
||||
logger: console as any,
|
||||
lifecycleEmitter: emitter,
|
||||
publisher,
|
||||
logger: console,
|
||||
defaultTimeoutMs: 2_000,
|
||||
});
|
||||
|
||||
@@ -111,9 +111,9 @@ describe('renderer overlay lifecycle integration', () => {
|
||||
const emitter = new MockAutomationLifecycleEmitter();
|
||||
const publisher = new RecordingPublisher();
|
||||
const svc = new OverlaySyncService({
|
||||
lifecycleEmitter: emitter as any,
|
||||
publisher: publisher as any,
|
||||
logger: console as any,
|
||||
lifecycleEmitter: emitter,
|
||||
publisher,
|
||||
logger: console,
|
||||
defaultTimeoutMs: 200,
|
||||
});
|
||||
|
||||
|
||||
@@ -5,8 +5,12 @@ import { OverlaySyncService } from 'packages/automation/application/services/Ove
|
||||
describe('renderer overlay integration', () => {
|
||||
test('renderer shows confirmed only after main acks confirmed', async () => {
|
||||
const emitter = new MockAutomationLifecycleEmitter()
|
||||
const publisher = { publish: async () => {} }
|
||||
const svc = new OverlaySyncService({ lifecycleEmitter: emitter as any, publisher: publisher as any, logger: console as any })
|
||||
const publisher: { publish: (event: unknown) => Promise<void> } = { publish: async () => {} }
|
||||
const svc = new OverlaySyncService({
|
||||
lifecycleEmitter: emitter,
|
||||
publisher,
|
||||
logger: console,
|
||||
})
|
||||
|
||||
// simulate renderer request
|
||||
const promise = svc.startAction({ id: 'add-car', label: 'Adding...' })
|
||||
|
||||
Reference in New Issue
Block a user