Skip to content

Commit

Permalink
fix: 🐛 when passing custom canvas, it still resets the original
Browse files Browse the repository at this point in the history
When passing custom canvas through Deck constructor, it still creates
the default one with reset and cursor hiding. This fix moves cursor
initialization into the constructor body, so that it resets and hides
cursor only and only when there is definitely no custom cursor in
constructor.
  • Loading branch information
ghaiklor committed May 11, 2020
1 parent 2224e57 commit 0748ffb
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 35 deletions.
98 changes: 67 additions & 31 deletions packages/kittik-deck/spec/Deck.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Deck, DeckDeclaration } from '../src/Deck';
import { Shape, ShapeRenderable } from 'kittik-shape-basic';
import { Animationable } from 'kittik-animation-basic';
import { Canvas } from 'terminal-canvas';
import { Print } from 'kittik-animation-print';
import { Slide } from 'kittik-slide';

Expand Down Expand Up @@ -47,16 +48,14 @@ const DECK_DECLARATION: DeckDeclaration = {
]
};

const AFTER_EACH = (deck: Deck): void => {
deck.exit();
};

describe('deck', () => {
it('should properly handle the key press for previous slide', async () => {
expect.hasAssertions();

const deck = new Deck(DECK_DECLARATION);
const canvas = Canvas.create();
const deck = new Deck(DECK_DECLARATION, canvas);
const renderSpy = jest.spyOn(deck, 'render').mockResolvedValue(true);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

await deck.nextSlide();
process.stdin.emit('keypress', 'p');
Expand All @@ -65,51 +64,63 @@ describe('deck', () => {
expect(renderSpy).toHaveBeenCalledWith(1);
expect(renderSpy).toHaveBeenCalledWith(0);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly handle the key press for next slide', () => {
expect.hasAssertions();

const deck = new Deck(DECK_DECLARATION);
const canvas = Canvas.create();
const deck = new Deck(DECK_DECLARATION, canvas);
const renderSpy = jest.spyOn(deck, 'render').mockResolvedValue(true);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

process.stdin.emit('keypress', 'n');

expect(renderSpy).toHaveBeenCalledTimes(1);
expect(renderSpy).toHaveBeenCalledWith(1);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly handle the key press for exit', () => {
expect.hasAssertions();

const deck = new Deck(DECK_DECLARATION);
const exitSpy = jest.spyOn(deck, 'exit').mockImplementation();
const canvas = Canvas.create();
const deck = new Deck(DECK_DECLARATION, canvas);
const exitSpy = jest.spyOn(deck, 'exit').mockImplementationOnce(() => true);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

process.stdin.emit('keypress', 'q');

expect(exitSpy).toHaveBeenCalledTimes(1);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should do nothing when unknown key has been pressed', () => {
expect.hasAssertions();

const deck = new Deck();
const canvas = Canvas.create();
const deck = new Deck(DECK_DECLARATION, canvas);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

expect(process.stdin.emit('keypress', '?')).toBe(true);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly render next and previous slides', async () => {
expect.hasAssertions();

const deck = new Deck(DECK_DECLARATION);
const canvas = Canvas.create();
const deck = new Deck(DECK_DECLARATION, canvas);
const renderSpy = jest.spyOn(deck, 'render').mockResolvedValue(true);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

await deck.nextSlide();
await deck.previousSlide();
Expand All @@ -118,14 +129,17 @@ describe('deck', () => {
expect(renderSpy).toHaveBeenCalledWith(1);
expect(renderSpy).toHaveBeenCalledWith(0);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly render slides without custom canvas', async () => {
expect.hasAssertions();

const deck = new Deck({ ...DECK_DECLARATION });
const canvas = Canvas.create();
const deck = new Deck({ ...DECK_DECLARATION }, canvas);
const renderSpy = jest.spyOn(deck, 'render').mockResolvedValue(true);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

await deck.nextSlide();
await deck.previousSlide();
Expand All @@ -134,12 +148,14 @@ describe('deck', () => {
expect(renderSpy).toHaveBeenCalledWith(1);
expect(renderSpy).toHaveBeenCalledWith(0);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly render minimal slide without global shapes/animations', async () => {
expect.hasAssertions();

const canvas = Canvas.create();
const deck = new Deck({
slides: [
{
Expand All @@ -154,9 +170,10 @@ describe('deck', () => {
animations: []
}
]
});
}, canvas);

const renderSpy = jest.spyOn(deck, 'render').mockResolvedValue(true);
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

await deck.nextSlide();
await deck.previousSlide();
Expand All @@ -165,21 +182,24 @@ describe('deck', () => {
expect(renderSpy).toHaveBeenCalledWith(1);
expect(renderSpy).toHaveBeenCalledWith(0);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should not call slide renderer many times if slide is already rendering', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const deck = new Deck({
slides: [{ name: 'Test', shapes: [], order: [] }]
});
}, canvas);

// Though, slides is a private property, I need to access it anyway in sake of the tests
// This is done to test if slides render() behaves as expected
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const renderSpy = jest.spyOn(deck.slides[0], 'render');
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

deck.render(); // eslint-disable-line @typescript-eslint/no-floating-promises
deck.render(); // eslint-disable-line @typescript-eslint/no-floating-promises
Expand All @@ -188,13 +208,16 @@ describe('deck', () => {

expect(renderSpy).toHaveBeenCalledTimes(1);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(0);
});

it('should properly add a shape to all the slides in the deck', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const shape: ShapeRenderable = new Shape();
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();
const deck = new Deck({
slides: [
{
Expand All @@ -203,7 +226,7 @@ describe('deck', () => {
order: []
}
]
});
}, canvas);

deck.addShape('Shape 2', shape);

Expand All @@ -212,13 +235,16 @@ describe('deck', () => {
// @ts-expect-error
expect(deck.slides[0].shapes.size).toBe(2);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly throw an error if shape already exists in other slides', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const shape: ShapeRenderable = new Shape();
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();
const deck = new Deck({
slides: [
{
Expand All @@ -227,7 +253,7 @@ describe('deck', () => {
order: []
}
]
});
}, canvas);

expect(() => deck.addShape('Shape', shape)).toThrow(
'You are trying to add a shape with the name "Shape" into the deck. ' +
Expand All @@ -236,13 +262,16 @@ describe('deck', () => {
'Remove the shape from the slides [Test] or rename the shape.'
);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly add an animation to all the slides in the deck', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const animation: Animationable = new Print();
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();
const deck = new Deck({
slides: [
{
Expand All @@ -252,7 +281,7 @@ describe('deck', () => {
animations: [{ name: 'Animation', type: 'Print' as const, options: {} }]
}
]
});
}, canvas);

deck.addAnimation('Animation 2', animation);

Expand All @@ -261,13 +290,16 @@ describe('deck', () => {
// @ts-expect-error
expect(deck.slides[0].animations.size).toBe(2);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly throw an error if animation already exists in other slides', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const animation: Animationable = new Print();
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();
const deck = new Deck({
slides: [
{
Expand All @@ -277,7 +309,7 @@ describe('deck', () => {
animations: [{ name: 'Animation', type: 'Print' as const, options: {} }]
}
]
});
}, canvas);

expect(() => deck.addAnimation('Animation', animation)).toThrow(
'You are trying to add an animation with the name "Animation" into the deck. ' +
Expand All @@ -286,12 +318,15 @@ describe('deck', () => {
'Remove the animations from the slides [Test] or rename the animation.'
);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});

it('should properly throw an error if name of the slide already exists in the deck', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();
const deck = new Deck({
slides: [
{
Expand All @@ -300,7 +335,7 @@ describe('deck', () => {
order: []
}
]
});
}, canvas);

const slide = new Slide();
slide.name = 'Slide #1';
Expand All @@ -311,6 +346,7 @@ describe('deck', () => {
'Remove the slide "Slide #1" from the deck or rename the slide you tried to add.'
);

AFTER_EACH(deck);
deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});
});
6 changes: 5 additions & 1 deletion packages/kittik-deck/spec/DeckBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ describe('deck builder', () => {
it('should properly create deck using DeckBuilder', () => {
expect.hasAssertions();

const canvas = Canvas.create();
const resetSpy = jest.spyOn(canvas, 'reset').mockReturnThis();

const PREDEFINED_SHAPES = { 'Test Shape': ShapeBuilder.start('Text').end() };
const PREDEFINED_ANIMATIONS = { 'Test Animation': AnimationBuilder.start('Focus').end() };
const deck = DeckBuilder
.start(PREDEFINED_SHAPES, PREDEFINED_ANIMATIONS)
.withCanvas(Canvas.create())
.withCanvas(canvas)
.withSlide(
(builder) => builder
.withName('Slide #1')
Expand Down Expand Up @@ -52,5 +55,6 @@ describe('deck builder', () => {
}]);

deck.exit();
expect(resetSpy).toHaveBeenCalledTimes(1);
});
});
8 changes: 5 additions & 3 deletions packages/kittik-deck/src/Deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ export declare interface Deck {
}

export class Deck extends EventEmitter {
public canvas: Canvas = Canvas.create().reset().hideCursor();
private readonly slides: Slide[] = [];
public canvas: Canvas;
private isRendering = false;
private currentSlideIndex = 0;
private readonly slides: Slide[] = [];

public constructor (declaration?: DeckDeclaration, canvas?: Canvas) {
super();

if (typeof canvas !== 'undefined') {
if (typeof canvas === 'undefined') {
this.canvas = Canvas.create().reset().hideCursor();
} else {
this.canvas = canvas;
}

Expand Down

0 comments on commit 0748ffb

Please sign in to comment.