Skip to content

Commit

Permalink
feat: add change between scenes test
Browse files Browse the repository at this point in the history
  • Loading branch information
fletcherist committed Aug 14, 2018
1 parent e259ada commit c3860e9
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 24 deletions.
13 changes: 8 additions & 5 deletions src/alice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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<IMiddlewareResult | null> => {
const middleware = middlewares[index];
index--;
return middleware(context, index < 0 ? null : next);
index++;
return middleware(
middlewareContext,
index >= middlewares.length ? null : next,
);
};
return next(context);
}
Expand Down
5 changes: 4 additions & 1 deletion src/session/sessionMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import { ISessionContext } from './sessionContext';

export function sessionMiddleware(
storage: ISessionStorage,
): Middleware<IContext, ISessionContext> {
): Middleware<ISessionContext, IContext> {
return async function(context, next): Promise<IMiddlewareResult | null> {
if (context.session) {
return next ? next(context) : null;
}
const id = context.data.session.session_id;
const session = await storage.getOrCreate(id);
const sessionContext: ISessionContext = {
Expand Down
7 changes: 5 additions & 2 deletions src/stage/compere.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -15,12 +16,14 @@ 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 {
this._context.session.set(
Stage.CURRENT_SCENE_SESSION_KEY,
Stage.DEFAULT_SCENE_NAME,
);
debug(`scene changed for: ${name}`);
}
}
1 change: 1 addition & 0 deletions src/stage/scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class Scene<TContext extends IStageContext = IStageContext>
}

public async run(context: TContext): Promise<CommandCallbackResult> {
console.log('runnig scene', this.name);
const command = await this._commands.getMostRelevant(context);
if (command) {
return command.run(context);
Expand Down
18 changes: 10 additions & 8 deletions src/stage/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<ISessionContext> {
return async (context, next): Promise<IMiddlewareResult> => {
return async (context, next): Promise<IMiddlewareResult | null> => {
if (!context.session) {
throw new Error(
'You have to add some session middelware to use scenes',
Expand All @@ -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;
};
}
Expand Down
5 changes: 3 additions & 2 deletions src/stage/stageContext.ts
Original file line number Diff line number Diff line change
@@ -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'];
}
54 changes: 48 additions & 6 deletions tests/scene.spec.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
4 changes: 4 additions & 0 deletions tests/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

0 comments on commit c3860e9

Please sign in to comment.