From c3860e9a964206fa52c1f12e5a5afce2fd37360a Mon Sep 17 00:00:00 2001 From: fletcherist Date: Tue, 14 Aug 2018 13:41:19 +0300 Subject: [PATCH] feat: add change between scenes test --- src/alice.ts | 13 +++++--- src/session/sessionMiddleware.ts | 5 ++- src/stage/compere.ts | 7 +++-- src/stage/scene.ts | 1 + src/stage/stage.ts | 18 ++++++----- src/stage/stageContext.ts | 5 +-- tests/scene.spec.ts | 54 ++++++++++++++++++++++++++++---- tests/testUtils.ts | 4 +++ 8 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/alice.ts b/src/alice.ts index f31cf5a..8b6239f 100644 --- a/src/alice.ts +++ b/src/alice.ts @@ -48,8 +48,8 @@ export class Alice implements IAlice { private _initMainStage( sessionsStorage: ISessionStorage = new InMemorySessionStorage(), ): void { - this.use(this._mainStage.middleware); this.use(sessionMiddleware(sessionsStorage)); + this.use(this._mainStage.middleware); } private async _runMiddlewares( @@ -60,13 +60,16 @@ export class Alice implements IAlice { return null; } - let index = middlewares.length - 1; + let index = 0; const next = async ( - context: IContext, + middlewareContext: IContext, ): Promise => { const middleware = middlewares[index]; - index--; - return middleware(context, index < 0 ? null : next); + index++; + return middleware( + middlewareContext, + index >= middlewares.length ? null : next, + ); }; return next(context); } diff --git a/src/session/sessionMiddleware.ts b/src/session/sessionMiddleware.ts index 4a29c4f..30a8618 100644 --- a/src/session/sessionMiddleware.ts +++ b/src/session/sessionMiddleware.ts @@ -5,8 +5,11 @@ import { ISessionContext } from './sessionContext'; export function sessionMiddleware( storage: ISessionStorage, -): Middleware { +): Middleware { return async function(context, next): Promise { + if (context.session) { + return next ? next(context) : null; + } const id = context.data.session.session_id; const session = await storage.getOrCreate(id); const sessionContext: ISessionContext = { diff --git a/src/stage/compere.ts b/src/stage/compere.ts index d5aaf60..4da432f 100644 --- a/src/stage/compere.ts +++ b/src/stage/compere.ts @@ -1,12 +1,13 @@ import { ISessionContext } from '../session/sessionContext'; import { Stage } from './stage'; +import debug from '../debug'; -export interface IStageСompere { +export interface IStageCompere { enter(name: string): void; leave(): void; } -export class StageСompere implements IStageСompere { +export class StageCompere implements IStageCompere { private readonly _context: ISessionContext; constructor(context: ISessionContext) { @@ -15,6 +16,7 @@ export class StageСompere implements IStageСompere { public enter(name: string): void { this._context.session.set(Stage.CURRENT_SCENE_SESSION_KEY, name); + debug(`scene changed for: ${name}`); } public leave(): void { @@ -22,5 +24,6 @@ export class StageСompere implements IStageСompere { Stage.CURRENT_SCENE_SESSION_KEY, Stage.DEFAULT_SCENE_NAME, ); + debug(`scene changed for: ${name}`); } } diff --git a/src/stage/scene.ts b/src/stage/scene.ts index d6364a1..bbbe0e9 100644 --- a/src/stage/scene.ts +++ b/src/stage/scene.ts @@ -42,6 +42,7 @@ export class Scene } public async run(context: TContext): Promise { + console.log('runnig scene', this.name); const command = await this._commands.getMostRelevant(context); if (command) { return command.run(context); diff --git a/src/stage/stage.ts b/src/stage/stage.ts index 2c91caa..15919df 100644 --- a/src/stage/stage.ts +++ b/src/stage/stage.ts @@ -2,7 +2,7 @@ import { IScene } from './scene'; import { Middleware, IMiddlewareResult } from '../middleware/middleware'; import { ISessionContext } from '../session/sessionContext'; import { IStageContext } from './stageContext'; -import { StageСompere } from './compere'; +import { StageCompere } from './compere'; import debug from '../debug'; export interface IStage { @@ -24,22 +24,22 @@ export class Stage implements IStage { public addScene(scene: IScene): void { if (this._scenes.has(scene.name)) { - throw new Error(`Duplicate scene name ${scene.name}`); + throw new Error(`Duplicate scene name "${scene.name}"`); } - debug(`scene added "${scene.name}"`); this._scenes.set(scene.name, scene); + debug(`scene added "${scene.name}"`); } public removeScene(name: string): void { if (!this._scenes.has(name)) { - throw new Error(`No scene with name ${name}`); + throw new Error(`No scene with name "${name}"`); } - debug(`scene removed "${name}"`); this._scenes.delete(name); + debug(`scene removed "${name}"`); } public getMiddleware(): Middleware { - return async (context, next): Promise => { + return async (context, next): Promise => { if (!context.session) { throw new Error( 'You have to add some session middelware to use scenes', @@ -54,16 +54,18 @@ export class Stage implements IStage { ? this._scenes.get(sceneName) : null; if (scene) { + const compere = new StageCompere(context); const stageContext: IStageContext = { ...context, - compere: new StageСompere(context), + enter: (name: string) => compere.enter(name), + leave: () => compere.leave(), }; + debug(`current scene "${scene.name}"`); const result = await scene.run(stageContext); return { responseBody: result, }; } - return next ? next(context) : null; }; } diff --git a/src/stage/stageContext.ts b/src/stage/stageContext.ts index 3927217..482f236 100644 --- a/src/stage/stageContext.ts +++ b/src/stage/stageContext.ts @@ -1,6 +1,7 @@ -import { IStageСompere } from './compere'; +import { IStageCompere } from './compere'; import { ISessionContext } from '../session/sessionContext'; export interface IStageContext extends ISessionContext { - readonly compere: IStageСompere; + readonly enter: IStageCompere['enter']; + readonly leave: IStageCompere['leave']; } diff --git a/tests/scene.spec.ts b/tests/scene.spec.ts index 9ef97b8..1076f7c 100644 --- a/tests/scene.spec.ts +++ b/tests/scene.spec.ts @@ -1,19 +1,61 @@ -import { Alice, Scene, Stage } from '../dist/'; -import { request, getRandomText } from './testUtils'; +import { Alice, Scene, Stage, sessionMiddleware, Reply } from '../dist/'; +import { request, getRandomText, delay } from './testUtils'; describe('alice scenes', () => { let alice = null; - let randomText = ''; let stage = null; + let randomText = ''; beforeEach(() => { alice = new Alice(); - randomText = getRandomText(); stage = new Stage(); + randomText = getRandomText(); }); - test('create new scene', () => { - const scene = new Scene('name'); + test('create new scene', async done => { + const scene = new Scene('bar'); + scene.any(ctx => ({ text: randomText })); stage.addScene(scene); + // alice.use(sessionMiddleware()); + alice.use(stage.getMiddleware()); + alice.any(async ctx => { + ctx.enter('bar'); + return { text: 'foo' }; + }); + // handling first request, leading to the scene "bar" + let data = await alice.handleRequest(request('hey!')); + expect(data.response.text).toBe('foo'); + // now looking for an answer from scene + data = await alice.handleRequest(request('hey!')); + expect(data.response.text).toBe(randomText); + done(); + }); + + test('switch between scenes', async done => { + const scene1 = new Scene('1'); + scene1.any(ctx => { + ctx.enter('2'); + return { text: 'scene1' }; + }); + const scene2 = new Scene('2'); + scene2.any(async ctx => { + ctx.leave(); + return { text: 'scene2' }; + }); + stage.addScene(scene1); + stage.addScene(scene2); alice.use(stage.getMiddleware()); + alice.any(async ctx => { + ctx.enter('1'); + return { text: 'alice' }; + }); + let data = await alice.handleRequest(request('baz')); + expect(data.response.text).toBe('alice'); + done(); + data = await alice.handleRequest(request('.')); + expect(data.response.text).toBe('scene1'); + data = await alice.handleRequest(request('.')); + expect(data.response.text).toBe('scene2'); + data = await alice.handleRequest(request('.')); + expect(data.response.text).toBe('alice'); }); }); diff --git a/tests/testUtils.ts b/tests/testUtils.ts index 6882099..468c447 100644 --- a/tests/testUtils.ts +++ b/tests/testUtils.ts @@ -29,3 +29,7 @@ export function getRandomText() { const words = ['ek', 'ong', 'kar', 'sat', 'gur', 'prasad']; return shuffle(words).join(' '); } + +export function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +}