From 0748ffb7e6d1557634da3515142cc301142efca7 Mon Sep 17 00:00:00 2001 From: Eugene Obrezkov Date: Mon, 11 May 2020 14:12:19 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20when=20passing=20custom?= =?UTF-8?q?=20canvas,=20it=20still=20resets=20the=20original?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- packages/kittik-deck/spec/Deck.spec.ts | 98 +++++++++++++------ packages/kittik-deck/spec/DeckBuilder.spec.ts | 6 +- packages/kittik-deck/src/Deck.ts | 8 +- 3 files changed, 77 insertions(+), 35 deletions(-) diff --git a/packages/kittik-deck/spec/Deck.spec.ts b/packages/kittik-deck/spec/Deck.spec.ts index cf7c94f..5f8094e 100644 --- a/packages/kittik-deck/spec/Deck.spec.ts +++ b/packages/kittik-deck/spec/Deck.spec.ts @@ -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'; @@ -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'); @@ -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(); @@ -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(); @@ -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: [ { @@ -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(); @@ -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 @@ -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: [ { @@ -203,7 +226,7 @@ describe('deck', () => { order: [] } ] - }); + }, canvas); deck.addShape('Shape 2', shape); @@ -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: [ { @@ -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. ' + @@ -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: [ { @@ -252,7 +281,7 @@ describe('deck', () => { animations: [{ name: 'Animation', type: 'Print' as const, options: {} }] } ] - }); + }, canvas); deck.addAnimation('Animation 2', animation); @@ -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: [ { @@ -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. ' + @@ -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: [ { @@ -300,7 +335,7 @@ describe('deck', () => { order: [] } ] - }); + }, canvas); const slide = new Slide(); slide.name = 'Slide #1'; @@ -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); }); }); diff --git a/packages/kittik-deck/spec/DeckBuilder.spec.ts b/packages/kittik-deck/spec/DeckBuilder.spec.ts index 2245a89..30a0a81 100644 --- a/packages/kittik-deck/spec/DeckBuilder.spec.ts +++ b/packages/kittik-deck/spec/DeckBuilder.spec.ts @@ -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') @@ -52,5 +55,6 @@ describe('deck builder', () => { }]); deck.exit(); + expect(resetSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/kittik-deck/src/Deck.ts b/packages/kittik-deck/src/Deck.ts index a0300d1..becd81a 100644 --- a/packages/kittik-deck/src/Deck.ts +++ b/packages/kittik-deck/src/Deck.ts @@ -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; }