From fd2055e2702251c856f60214f150c78d558dcbf7 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 28 Nov 2020 10:22:26 +0900 Subject: Make HintKeyRepository --- test/content/usecases/HintKeyProducer.test.ts | 33 +++++++++++++++++++-------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'test') diff --git a/test/content/usecases/HintKeyProducer.test.ts b/test/content/usecases/HintKeyProducer.test.ts index f7e02ea..9d320b4 100644 --- a/test/content/usecases/HintKeyProducer.test.ts +++ b/test/content/usecases/HintKeyProducer.test.ts @@ -1,13 +1,7 @@ -import HintKeyProducer from "../../../src/content/usecases/HintKeyProducer"; +import { HintKeyRepositoryImpl } from "../../../src/content/repositories/HintKeyRepository"; import { expect } from "chai"; -describe("HintKeyProducer class", () => { - describe("#constructor", () => { - it("throws an exception on empty charset", () => { - expect(() => new HintKeyProducer("")).to.throw(TypeError); - }); - }); - +describe("HintKeyProducerImpl class", () => { describe("#produce", () => { it("produce incremented keys", () => { const charset = "abc"; @@ -30,10 +24,29 @@ describe("HintKeyProducer class", () => { "aba", ]; - const producer = new HintKeyProducer(charset); + const sut = new HintKeyRepositoryImpl(); + sut.reset(charset); for (let i = 0; i < sequences.length; ++i) { - expect(producer.produce()).to.equal(sequences[i]); + expect(sut.produce()).to.equal(sequences[i]); } }); }); + + describe("#reset", () => { + it("resets charset", () => { + const sut = new HintKeyRepositoryImpl(); + + sut.reset("ab"); + expect(sut.produce()).to.equal("a"); + expect(sut.produce()).to.equal("b"); + + sut.reset("xy"); + expect(sut.produce()).to.equal("x"); + expect(sut.produce()).to.equal("y"); + }); + it("throws an exception on empty charset", () => { + const sut = new HintKeyRepositoryImpl(); + expect(() => sut.reset("")).to.throw(TypeError); + }); + }); }); -- cgit v1.2.3 From c523d75472a16dc58e2e4c4ee51eb15efe6c11f9 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 29 Nov 2020 13:55:26 +0900 Subject: Add operators' test --- src/content/di.ts | 2 + .../impls/ClipboardOperatorFactoryChain.ts | 8 +++- src/content/operators/impls/FindNextOperator.ts | 9 +++- .../operators/impls/FindOperatorFactoryChain.ts | 11 +---- src/content/operators/impls/FindPrevOperator.ts | 9 +++- src/content/operators/impls/RepeatOperator.ts | 14 ------ src/content/operators/impls/URLRepository.ts | 9 ++++ src/content/operators/impls/YankURLOperator.ts | 6 ++- test/content/mock/MockAddonEnabledRepository.ts | 18 ++++++++ test/content/mock/MockAddonIndicatorClient.ts | 13 ++++++ test/content/mock/MockClipboardRepository.ts | 16 +++++++ test/content/mock/MockFindMasterClient.ts | 11 +++++ test/content/mock/MockFocusPresenter.ts | 7 +++ test/content/mock/MockFollowMasterClient.ts | 16 +++++++ test/content/mock/MockMarkKeyRepository.ts | 43 ++++++++++++++++++ test/content/mock/MockOperationClient.ts | 16 +++++++ test/content/mock/MockScrollPresenter.ts | 6 +-- test/content/mock/MockSettingRepository.ts | 20 +++++++++ test/content/mock/MockURLRepository.ts | 9 ++++ .../impls/AddonOperatorFactoryChain.test.ts | 29 ++++++++++++ .../impls/BackgroundOperationOperator.test.ts | 38 ++++++++++++++++ .../impls/ClipboardOperatorFactoryChain.test.ts | 31 +++++++++++++ .../operators/impls/DisableAddonOperator.test.ts | 19 ++++++++ .../operators/impls/EnableAddonOperator.test.ts | 19 ++++++++ .../operators/impls/EnableJumpMarkOperator.test.ts | 19 ++++++++ .../operators/impls/EnableSetMarkOperator.test.ts | 19 ++++++++ .../operators/impls/FindNextOperator.test.ts | 17 ++++++++ .../impls/FindOperatorFactoryChain.test.ts | 21 +++++++++ .../operators/impls/FindPrevOperator.test.ts | 17 ++++++++ test/content/operators/impls/FocusOperator.test.ts | 17 ++++++++ .../impls/FocusOperatorFactoryChain.test.ts | 17 ++++++++ .../impls/FollowOperatorFactoryChain.test.ts | 20 +++++++++ .../impls/HorizontalScrollOperator.test.ts | 28 ++++++++++++ .../impls/MarkOperatorFactoryChain.test.ts | 21 +++++++++ .../operators/impls/PageScrollOperator.test.ts | 28 ++++++++++++ test/content/operators/impls/PasteOperator.test.ts | 51 ++++++++++++++++++++++ .../impls/ScrollOperatorFactoryChain.test.ts | 46 +++++++++++++++++++ .../operators/impls/ScrollToBottomOperator.test.ts | 18 ++++++++ .../operators/impls/ScrollToEndOperator.test.ts | 18 ++++++++ .../operators/impls/ScrollToHomeOperator.test.ts | 18 ++++++++ .../operators/impls/ScrollToTopOperator.test.ts | 18 ++++++++ .../operators/impls/StartFollowOperator.test.ts | 20 +++++++++ .../operators/impls/ToggleAddonOperator.test.ts | 24 ++++++++++ .../operators/impls/VerticalScrollOperator.test.ts | 28 ++++++++++++ .../operators/impls/YankURLOperator.test.ts | 26 +++++++++++ 45 files changed, 836 insertions(+), 34 deletions(-) delete mode 100644 src/content/operators/impls/RepeatOperator.ts create mode 100644 src/content/operators/impls/URLRepository.ts create mode 100644 test/content/mock/MockAddonEnabledRepository.ts create mode 100644 test/content/mock/MockAddonIndicatorClient.ts create mode 100644 test/content/mock/MockClipboardRepository.ts create mode 100644 test/content/mock/MockFindMasterClient.ts create mode 100644 test/content/mock/MockFocusPresenter.ts create mode 100644 test/content/mock/MockFollowMasterClient.ts create mode 100644 test/content/mock/MockMarkKeyRepository.ts create mode 100644 test/content/mock/MockOperationClient.ts create mode 100644 test/content/mock/MockSettingRepository.ts create mode 100644 test/content/mock/MockURLRepository.ts create mode 100644 test/content/operators/impls/AddonOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/BackgroundOperationOperator.test.ts create mode 100644 test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/DisableAddonOperator.test.ts create mode 100644 test/content/operators/impls/EnableAddonOperator.test.ts create mode 100644 test/content/operators/impls/EnableJumpMarkOperator.test.ts create mode 100644 test/content/operators/impls/EnableSetMarkOperator.test.ts create mode 100644 test/content/operators/impls/FindNextOperator.test.ts create mode 100644 test/content/operators/impls/FindOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/FindPrevOperator.test.ts create mode 100644 test/content/operators/impls/FocusOperator.test.ts create mode 100644 test/content/operators/impls/FocusOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/FollowOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/HorizontalScrollOperator.test.ts create mode 100644 test/content/operators/impls/MarkOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/PageScrollOperator.test.ts create mode 100644 test/content/operators/impls/PasteOperator.test.ts create mode 100644 test/content/operators/impls/ScrollOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/ScrollToBottomOperator.test.ts create mode 100644 test/content/operators/impls/ScrollToEndOperator.test.ts create mode 100644 test/content/operators/impls/ScrollToHomeOperator.test.ts create mode 100644 test/content/operators/impls/ScrollToTopOperator.test.ts create mode 100644 test/content/operators/impls/StartFollowOperator.test.ts create mode 100644 test/content/operators/impls/ToggleAddonOperator.test.ts create mode 100644 test/content/operators/impls/VerticalScrollOperator.test.ts create mode 100644 test/content/operators/impls/YankURLOperator.test.ts (limited to 'test') diff --git a/src/content/di.ts b/src/content/di.ts index b39ce54..e74d7ac 100644 --- a/src/content/di.ts +++ b/src/content/di.ts @@ -30,6 +30,7 @@ import { SettingRepositoryImpl } from "./repositories/SettingRepository"; import { TabsClientImpl } from "./client/TabsClient"; import { container } from "tsyringe"; import OperatorFactoryImpl from "./operators/impls/OperatorFactoryImpl"; +import { URLRepositoryImpl } from "./operators/impls/URLRepository"; container.register("FollowMasterClient", { useValue: new FollowMasterClientImpl(window.top), @@ -80,5 +81,6 @@ container.register("OperationClient", { useClass: OperationClientImpl }); container.register("ScrollPresenter", { useClass: ScrollPresenterImpl }); container.register("SettingClient", { useClass: SettingClientImpl }); container.register("SettingRepository", { useClass: SettingRepositoryImpl }); +container.register("URLRepository", { useClass: URLRepositoryImpl }); container.register("TabsClient", { useClass: TabsClientImpl }); container.register("OperatorFactory", { useClass: OperatorFactoryImpl }); diff --git a/src/content/operators/impls/ClipboardOperatorFactoryChain.ts b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts index fb12ae8..454aea1 100644 --- a/src/content/operators/impls/ClipboardOperatorFactoryChain.ts +++ b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts @@ -8,6 +8,7 @@ import ConsoleClient from "../../client/ConsoleClient"; import OperationClient from "../../client/OperationClient"; import SettingRepository from "../../repositories/SettingRepository"; import * as operations from "../../../shared/operations"; +import URLRepository from "./URLRepository"; @injectable() export default class ClipboardOperatorFactoryChain @@ -20,7 +21,9 @@ export default class ClipboardOperatorFactoryChain @inject("OperationClient") private readonly operationClinet: OperationClient, @inject("SettingRepository") - private readonly settingRepository: SettingRepository + private readonly settingRepository: SettingRepository, + @inject("URLRepository") + private readonly urlRepository: URLRepository ) {} create(op: operations.Operation, _repeat: number): Operator | null { @@ -28,7 +31,8 @@ export default class ClipboardOperatorFactoryChain case operations.URLS_YANK: return new YankURLOperator( this.clipboardRepository, - this.consoleClient + this.consoleClient, + this.urlRepository ); case operations.URLS_PASTE: return new PasteOperator( diff --git a/src/content/operators/impls/FindNextOperator.ts b/src/content/operators/impls/FindNextOperator.ts index 723db3d..c67f6d9 100644 --- a/src/content/operators/impls/FindNextOperator.ts +++ b/src/content/operators/impls/FindNextOperator.ts @@ -2,9 +2,14 @@ import Operator from "../Operator"; import FindMasterClient from "../../client/FindMasterClient"; export default class FindNextOperator implements Operator { - constructor(private readonly findMasterClient: FindMasterClient) {} + constructor( + private readonly findMasterClient: FindMasterClient, + private readonly repeat: number + ) {} async run(): Promise { - this.findMasterClient.findNext(); + for (let i = 0; i < this.repeat; ++i) { + this.findMasterClient.findNext(); + } } } diff --git a/src/content/operators/impls/FindOperatorFactoryChain.ts b/src/content/operators/impls/FindOperatorFactoryChain.ts index ef1c754..b3524c1 100644 --- a/src/content/operators/impls/FindOperatorFactoryChain.ts +++ b/src/content/operators/impls/FindOperatorFactoryChain.ts @@ -1,7 +1,6 @@ import { inject, injectable } from "tsyringe"; import Operator from "../Operator"; import OperatorFactoryChain from "../OperatorFactoryChain"; -import RepeatOperator from "./RepeatOperator"; import FindNextOperator from "./FindNextOperator"; import FindPrevOperator from "./FindPrevOperator"; import FindMasterClient from "../../client/FindMasterClient"; @@ -17,15 +16,9 @@ export default class FindOperatorFactoryChain implements OperatorFactoryChain { create(op: operations.Operation, repeat: number): Operator | null { switch (op.type) { case operations.FIND_NEXT: - return new RepeatOperator( - new FindNextOperator(this.findMasterClient), - repeat - ); + return new FindNextOperator(this.findMasterClient, repeat); case operations.FIND_PREV: - return new RepeatOperator( - new FindPrevOperator(this.findMasterClient), - repeat - ); + return new FindPrevOperator(this.findMasterClient, repeat); } return null; } diff --git a/src/content/operators/impls/FindPrevOperator.ts b/src/content/operators/impls/FindPrevOperator.ts index be6a01e..f73e605 100644 --- a/src/content/operators/impls/FindPrevOperator.ts +++ b/src/content/operators/impls/FindPrevOperator.ts @@ -2,9 +2,14 @@ import Operator from "../Operator"; import FindMasterClient from "../../client/FindMasterClient"; export default class FindPrevOperator implements Operator { - constructor(private readonly findMasterClient: FindMasterClient) {} + constructor( + private readonly findMasterClient: FindMasterClient, + private readonly repeat: number + ) {} async run(): Promise { - this.findMasterClient.findPrev(); + for (let i = 0; i < this.repeat; ++i) { + this.findMasterClient.findPrev(); + } } } diff --git a/src/content/operators/impls/RepeatOperator.ts b/src/content/operators/impls/RepeatOperator.ts deleted file mode 100644 index efe2faf..0000000 --- a/src/content/operators/impls/RepeatOperator.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Operator from "../Operator"; - -export default class RepeatOperator implements Operator { - constructor( - private readonly operator: Operator, - private readonly repeat: number - ) {} - - async run(): Promise { - for (let i = 0; i < this.repeat; ++i) { - this.operator.run(); - } - } -} diff --git a/src/content/operators/impls/URLRepository.ts b/src/content/operators/impls/URLRepository.ts new file mode 100644 index 0000000..a1efc2e --- /dev/null +++ b/src/content/operators/impls/URLRepository.ts @@ -0,0 +1,9 @@ +export default interface URLRepository { + getCurrentURL(): string; +} + +export class URLRepositoryImpl implements URLRepository { + getCurrentURL(): string { + return window.location.href; + } +} diff --git a/src/content/operators/impls/YankURLOperator.ts b/src/content/operators/impls/YankURLOperator.ts index 5e2ac60..2e774eb 100644 --- a/src/content/operators/impls/YankURLOperator.ts +++ b/src/content/operators/impls/YankURLOperator.ts @@ -1,15 +1,17 @@ import Operator from "../Operator"; import ClipboardRepository from "../../repositories/ClipboardRepository"; import ConsoleClient from "../../client/ConsoleClient"; +import URLRepository from "./URLRepository"; export default class YankURLOperator implements Operator { constructor( private readonly repository: ClipboardRepository, - private readonly consoleClient: ConsoleClient + private readonly consoleClient: ConsoleClient, + private readonly urlRepository: URLRepository ) {} async run(): Promise { - const url = window.location.href; + const url = this.urlRepository.getCurrentURL(); this.repository.write(url); await this.consoleClient.info("Yanked " + url); } diff --git a/test/content/mock/MockAddonEnabledRepository.ts b/test/content/mock/MockAddonEnabledRepository.ts new file mode 100644 index 0000000..cbe248b --- /dev/null +++ b/test/content/mock/MockAddonEnabledRepository.ts @@ -0,0 +1,18 @@ +import AddonEnabledRepository from "../../../src/content/repositories/AddonEnabledRepository"; + +export default class MockAddonEnabledRepository + implements AddonEnabledRepository { + public enabled: boolean; + + constructor(initialValue = false) { + this.enabled = initialValue; + } + + get(): boolean { + return this.enabled; + } + + set(on: boolean): void { + this.enabled = on; + } +} diff --git a/test/content/mock/MockAddonIndicatorClient.ts b/test/content/mock/MockAddonIndicatorClient.ts new file mode 100644 index 0000000..6ea9798 --- /dev/null +++ b/test/content/mock/MockAddonIndicatorClient.ts @@ -0,0 +1,13 @@ +import AddonIndicatorClient from "../../../src/content/client/AddonIndicatorClient"; + +export default class MockAddonIndicatorClient implements AddonIndicatorClient { + public enabled: boolean; + + constructor(initialValue = false) { + this.enabled = initialValue; + } + + async setEnabled(enabled: boolean): Promise { + this.enabled = enabled; + } +} diff --git a/test/content/mock/MockClipboardRepository.ts b/test/content/mock/MockClipboardRepository.ts new file mode 100644 index 0000000..c6e53bd --- /dev/null +++ b/test/content/mock/MockClipboardRepository.ts @@ -0,0 +1,16 @@ +import ClipboardRepository from "../../../src/content/repositories/ClipboardRepository"; + +export default class MockClipboardRepository implements ClipboardRepository { + private value: string; + + constructor(initValue = "") { + this.value = initValue; + } + read(): string { + return this.value; + } + + write(text: string): void { + this.value = text; + } +} diff --git a/test/content/mock/MockFindMasterClient.ts b/test/content/mock/MockFindMasterClient.ts new file mode 100644 index 0000000..a035cc5 --- /dev/null +++ b/test/content/mock/MockFindMasterClient.ts @@ -0,0 +1,11 @@ +import FindMasterClient from "../../../src/content/client/FindMasterClient"; + +export default class MockFindMasterClient implements FindMasterClient { + findNext(): void { + throw new Error("not implemented"); + } + + findPrev(): void { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockFocusPresenter.ts b/test/content/mock/MockFocusPresenter.ts new file mode 100644 index 0000000..43454d0 --- /dev/null +++ b/test/content/mock/MockFocusPresenter.ts @@ -0,0 +1,7 @@ +import FocusPresenter from "../../../src/content/presenters/FocusPresenter"; + +export default class MockFocusPresenter implements FocusPresenter { + focusFirstElement(): boolean { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockFollowMasterClient.ts b/test/content/mock/MockFollowMasterClient.ts new file mode 100644 index 0000000..fc660d5 --- /dev/null +++ b/test/content/mock/MockFollowMasterClient.ts @@ -0,0 +1,16 @@ +import FollowMasterClient from "../../../src/content/client/FollowMasterClient"; +import Key from "../../../src/shared/settings/Key"; + +export default class MockFollowMasterClient implements FollowMasterClient { + responseHintCount(_count: number): void { + throw new Error("not implemented"); + } + + sendKey(_key: Key): void { + throw new Error("not implemented"); + } + + startFollow(_newTab: boolean, _background: boolean): void { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockMarkKeyRepository.ts b/test/content/mock/MockMarkKeyRepository.ts new file mode 100644 index 0000000..12bc75c --- /dev/null +++ b/test/content/mock/MockMarkKeyRepository.ts @@ -0,0 +1,43 @@ +import MarkKeyRepository from "../../../src/content/repositories/MarkKeyRepository"; + +export default class MockMarkKeyRepository implements MarkKeyRepository { + public jumpMode: boolean; + public setMode: boolean; + + constructor( + initialValue: { + jumpMode: boolean; + setMode: boolean; + } = { + jumpMode: false, + setMode: false, + } + ) { + this.jumpMode = initialValue.jumpMode; + this.setMode = initialValue.setMode; + } + + disabeJumpMode(): void { + this.jumpMode = false; + } + + disabeSetMode(): void { + this.setMode = false; + } + + enableJumpMode(): void { + this.jumpMode = true; + } + + enableSetMode(): void { + this.setMode = true; + } + + isJumpMode(): boolean { + return this.jumpMode; + } + + isSetMode(): boolean { + return this.setMode; + } +} diff --git a/test/content/mock/MockOperationClient.ts b/test/content/mock/MockOperationClient.ts new file mode 100644 index 0000000..2f50f77 --- /dev/null +++ b/test/content/mock/MockOperationClient.ts @@ -0,0 +1,16 @@ +import OperationClient from "../../../src/content/client/OperationClient"; +import * as operations from "../../../src/shared/operations"; + +export default class MockOperationClient implements OperationClient { + execBackgroundOp(_repeat: number, _op: operations.Operation): Promise { + throw new Error("not implemented"); + } + + internalOpenUrl( + _url: string, + _newTab?: boolean, + _background?: boolean + ): Promise { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockScrollPresenter.ts b/test/content/mock/MockScrollPresenter.ts index c802227..8b4cf2a 100644 --- a/test/content/mock/MockScrollPresenter.ts +++ b/test/content/mock/MockScrollPresenter.ts @@ -3,10 +3,10 @@ import ScrollPresenter, { } from "../../../src/content/presenters/ScrollPresenter"; export default class MockScrollPresenter implements ScrollPresenter { - private pos: Point; + private readonly pos: Point; - constructor() { - this.pos = { x: 0, y: 0 }; + constructor(initX = 0, initY = 0) { + this.pos = { x: initX, y: initY }; } getScroll(): Point { diff --git a/test/content/mock/MockSettingRepository.ts b/test/content/mock/MockSettingRepository.ts new file mode 100644 index 0000000..5242713 --- /dev/null +++ b/test/content/mock/MockSettingRepository.ts @@ -0,0 +1,20 @@ +import SettingRepository from "../../../src/content/repositories/SettingRepository"; +import Settings, { + DefaultSetting, +} from "../../../src/shared/settings/Settings"; + +export default class MockSettingRepository implements SettingRepository { + private value: Settings; + + constructor(initValue: Settings = DefaultSetting) { + this.value = initValue; + } + + get(): Settings { + return this.value; + } + + set(setting: Settings): void { + this.value = setting; + } +} diff --git a/test/content/mock/MockURLRepository.ts b/test/content/mock/MockURLRepository.ts new file mode 100644 index 0000000..731a7fb --- /dev/null +++ b/test/content/mock/MockURLRepository.ts @@ -0,0 +1,9 @@ +import URLRepository from "../../../src/content/operators/impls/URLRepository"; + +export default class MockURLRepository implements URLRepository { + constructor(private url: string = "https://example.com/") {} + + getCurrentURL(): string { + return this.url; + } +} diff --git a/test/content/operators/impls/AddonOperatorFactoryChain.test.ts b/test/content/operators/impls/AddonOperatorFactoryChain.test.ts new file mode 100644 index 0000000..c064bb9 --- /dev/null +++ b/test/content/operators/impls/AddonOperatorFactoryChain.test.ts @@ -0,0 +1,29 @@ +import AddonOperatorFactoryChain from "../../../../src/content/operators/impls/AddonOperatorFactoryChain"; +import EnableAddonOperator from "../../../../src/content/operators/impls/EnableAddonOperator"; +import DisableAddonOperator from "../../../../src/content/operators/impls/DisableAddonOperator"; +import ToggleAddonOperator from "../../../../src/content/operators/impls/ToggleAddonOperator"; +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("AddonOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new AddonOperatorFactoryChain( + new MockAddonIndicatorClient(), + new MockAddonEnabledRepository() + ); + expect(sut.create({ type: operations.ADDON_ENABLE }, 0)).to.be.instanceOf( + EnableAddonOperator + ); + expect( + sut.create({ type: operations.ADDON_DISABLE }, 0) + ).to.be.instanceOf(DisableAddonOperator); + expect( + sut.create({ type: operations.ADDON_TOGGLE_ENABLED }, 0) + ).to.be.instanceOf(ToggleAddonOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/BackgroundOperationOperator.test.ts b/test/content/operators/impls/BackgroundOperationOperator.test.ts new file mode 100644 index 0000000..b8b1fbd --- /dev/null +++ b/test/content/operators/impls/BackgroundOperationOperator.test.ts @@ -0,0 +1,38 @@ +import * as operations from "../../../../src/shared/operations"; +import BackgroundOperationOperator from "../../../../src/content/operators/impls/BackgroundOperationOperator"; +import OperationClient from "../../../../src/content/client/OperationClient"; +import { expect } from "chai"; + +class MockOperationClient implements OperationClient { + public readonly executedOps: { + op: operations.Operation; + repeat: number; + }[] = []; + async execBackgroundOp( + repeat: number, + op: operations.Operation + ): Promise { + this.executedOps.push({ repeat, op }); + } + + internalOpenUrl(): Promise { + throw new Error("not implemented"); + } +} + +describe("BackgroundOperationOperator", () => { + describe("#run", () => { + it("returns an operator", async () => { + const client = new MockOperationClient(); + const sut = new BackgroundOperationOperator(client, 2, { + type: operations.TAB_CLOSE, + }); + + await sut.run(); + + expect(client.executedOps).to.deep.equal([ + { op: { type: operations.TAB_CLOSE }, repeat: 2 }, + ]); + }); + }); +}); diff --git a/test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts b/test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts new file mode 100644 index 0000000..9ddc229 --- /dev/null +++ b/test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts @@ -0,0 +1,31 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import ClipboardOperatorFactoryChain from "../../../../src/content/operators/impls/ClipboardOperatorFactoryChain"; +import YankURLOperator from "../../../../src/content/operators/impls/YankURLOperator"; +import PasteOperator from "../../../../src/content/operators/impls/PasteOperator"; +import MockClipboardRepository from "../../mock/MockClipboardRepository"; +import MockOperationClient from "../../mock/MockOperationClient"; +import MockSettingRepository from "../../mock/MockSettingRepository"; +import MockConsoleClient from "../../mock/MockConsoleClient"; +import MockURLRepository from "../../mock/MockURLRepository"; + +describe("ClipboardOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new ClipboardOperatorFactoryChain( + new MockClipboardRepository(), + new MockConsoleClient(), + new MockOperationClient(), + new MockSettingRepository(), + new MockURLRepository() + ); + expect(sut.create({ type: operations.URLS_YANK }, 0)).to.be.instanceOf( + YankURLOperator + ); + expect( + sut.create({ type: operations.URLS_PASTE, newTab: false }, 0) + ).to.be.instanceOf(PasteOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/DisableAddonOperator.test.ts b/test/content/operators/impls/DisableAddonOperator.test.ts new file mode 100644 index 0000000..358ae44 --- /dev/null +++ b/test/content/operators/impls/DisableAddonOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import DisableAddonOperator from "../../../../src/content/operators/impls/DisableAddonOperator"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("DisableAddonOperator", () => { + describe("#run", () => { + it("disables addon", async () => { + const client = new MockAddonIndicatorClient(true); + const repository = new MockAddonEnabledRepository(true); + const sut = new DisableAddonOperator(client, repository); + + await sut.run(); + + expect(client.enabled).to.be.false; + expect(repository.enabled).to.be.false; + }); + }); +}); diff --git a/test/content/operators/impls/EnableAddonOperator.test.ts b/test/content/operators/impls/EnableAddonOperator.test.ts new file mode 100644 index 0000000..a6ca31b --- /dev/null +++ b/test/content/operators/impls/EnableAddonOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import EnableAddonOperator from "../../../../src/content/operators/impls/EnableAddonOperator"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("EnableAddonOperator", () => { + describe("#run", () => { + it("enabled addon", async () => { + const client = new MockAddonIndicatorClient(false); + const repository = new MockAddonEnabledRepository(false); + const sut = new EnableAddonOperator(client, repository); + + await sut.run(); + + expect(client.enabled).to.be.true; + expect(repository.enabled).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/EnableJumpMarkOperator.test.ts b/test/content/operators/impls/EnableJumpMarkOperator.test.ts new file mode 100644 index 0000000..66b4ecd --- /dev/null +++ b/test/content/operators/impls/EnableJumpMarkOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import EnableJumpMarkOperator from "../../../../src/content/operators/impls/EnableJumpMarkOperator"; +import MockMarkKeyRepository from "../../mock/MockMarkKeyRepository"; + +describe("EnableJumpMarkOperator", () => { + describe("#run", () => { + it("starts mark jump mode", async () => { + const repository = new MockMarkKeyRepository({ + jumpMode: false, + setMode: false, + }); + const sut = new EnableJumpMarkOperator(repository); + + await sut.run(); + + expect(repository.jumpMode).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/EnableSetMarkOperator.test.ts b/test/content/operators/impls/EnableSetMarkOperator.test.ts new file mode 100644 index 0000000..b28874d --- /dev/null +++ b/test/content/operators/impls/EnableSetMarkOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import EnableSetMarkOperator from "../../../../src/content/operators/impls/EnableSetMarkOperator"; +import MockMarkKeyRepository from "../../mock/MockMarkKeyRepository"; + +describe("EnableSetMarkOperator", () => { + describe("#run", () => { + it("starts mark set mode", async () => { + const repository = new MockMarkKeyRepository({ + jumpMode: false, + setMode: false, + }); + const sut = new EnableSetMarkOperator(repository); + + await sut.run(); + + expect(repository.setMode).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/FindNextOperator.test.ts b/test/content/operators/impls/FindNextOperator.test.ts new file mode 100644 index 0000000..d93d45e --- /dev/null +++ b/test/content/operators/impls/FindNextOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import FindNextOperator from "../../../../src/content/operators/impls/FindNextOperator"; +import MockFindMasterClient from "../../mock/MockFindMasterClient"; + +describe("FindNextOperator", () => { + describe("#run", () => { + it("find next keyword", async () => { + const client = new MockFindMasterClient(); + const mock = sinon.mock(client).expects("findNext").exactly(3); + const sut = new FindNextOperator(client, 3); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/FindOperatorFactoryChain.test.ts b/test/content/operators/impls/FindOperatorFactoryChain.test.ts new file mode 100644 index 0000000..6c599ae --- /dev/null +++ b/test/content/operators/impls/FindOperatorFactoryChain.test.ts @@ -0,0 +1,21 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import FindOperatorFactoryChain from "../../../../src/content/operators/impls/FindOperatorFactoryChain"; +import MockFindMasterClient from "../../mock/MockFindMasterClient"; +import FindNextOperator from "../../../../src/content/operators/impls/FindNextOperator"; +import FindPrevOperator from "../../../../src/content/operators/impls/FindPrevOperator"; + +describe("FindOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new FindOperatorFactoryChain(new MockFindMasterClient()); + expect(sut.create({ type: operations.FIND_NEXT }, 0)).to.be.instanceOf( + FindNextOperator + ); + expect(sut.create({ type: operations.FIND_PREV }, 0)).to.be.instanceOf( + FindPrevOperator + ); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/FindPrevOperator.test.ts b/test/content/operators/impls/FindPrevOperator.test.ts new file mode 100644 index 0000000..1ebde8d --- /dev/null +++ b/test/content/operators/impls/FindPrevOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import FindPrevOperator from "../../../../src/content/operators/impls/FindPrevOperator"; +import MockFindMasterClient from "../../mock/MockFindMasterClient"; + +describe("FindPrevOperator", () => { + describe("#run", () => { + it("find previous keyword", async () => { + const client = new MockFindMasterClient(); + const mock = sinon.mock(client).expects("findPrev").exactly(3); + const sut = new FindPrevOperator(client, 3); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/FocusOperator.test.ts b/test/content/operators/impls/FocusOperator.test.ts new file mode 100644 index 0000000..a0eb53b --- /dev/null +++ b/test/content/operators/impls/FocusOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import FocusOperator from "../../../../src/content/operators/impls/FocusOperator"; +import MockFocusPresenter from "../../mock/MockFocusPresenter"; + +describe("FocusOperator", () => { + describe("#run", () => { + it("focus a first input", async () => { + const presenter = new MockFocusPresenter(); + const mock = sinon.mock(presenter).expects("focusFirstElement"); + const sut = new FocusOperator(presenter); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/FocusOperatorFactoryChain.test.ts b/test/content/operators/impls/FocusOperatorFactoryChain.test.ts new file mode 100644 index 0000000..91f734b --- /dev/null +++ b/test/content/operators/impls/FocusOperatorFactoryChain.test.ts @@ -0,0 +1,17 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import FocusOperatorFactoryChain from "../../../../src/content/operators/impls/FocusOperatorFactoryChain"; +import FocusOperator from "../../../../src/content/operators/impls/FocusOperator"; +import MockFocusPresenter from "../../mock/MockFocusPresenter"; + +describe("FocusOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new FocusOperatorFactoryChain(new MockFocusPresenter()); + expect(sut.create({ type: operations.FOCUS_INPUT }, 0)).to.be.instanceOf( + FocusOperator + ); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/FollowOperatorFactoryChain.test.ts b/test/content/operators/impls/FollowOperatorFactoryChain.test.ts new file mode 100644 index 0000000..526a93c --- /dev/null +++ b/test/content/operators/impls/FollowOperatorFactoryChain.test.ts @@ -0,0 +1,20 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import FocusOperatorFactoryChain from "../../../../src/content/operators/impls/FocusOperatorFactoryChain"; +import FocusOperator from "../../../../src/content/operators/impls/FocusOperator"; +import MockFocusPresenter from "../../mock/MockFocusPresenter"; + +describe("FocusOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new FocusOperatorFactoryChain(new MockFocusPresenter()); + expect( + sut.create( + { type: operations.FOCUS_INPUT, newTab: false, background: false }, + 0 + ) + ).to.be.instanceOf(FocusOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/HorizontalScrollOperator.test.ts b/test/content/operators/impls/HorizontalScrollOperator.test.ts new file mode 100644 index 0000000..f77a34e --- /dev/null +++ b/test/content/operators/impls/HorizontalScrollOperator.test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import HorizontalScrollOperator from "../../../../src/content/operators/impls/HorizontalScrollOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("HorizontalScrollOperator", () => { + describe("#run", () => { + it("scroll horizontally", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new HorizontalScrollOperator(presenter, settingRepository, 1); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 1, y: 0 }); + }); + + it("scroll horizontally with repeats", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new HorizontalScrollOperator(presenter, settingRepository, 5); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 5, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/MarkOperatorFactoryChain.test.ts b/test/content/operators/impls/MarkOperatorFactoryChain.test.ts new file mode 100644 index 0000000..1f094dd --- /dev/null +++ b/test/content/operators/impls/MarkOperatorFactoryChain.test.ts @@ -0,0 +1,21 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import MarkOperatorFactoryChain from "../../../../src/content/operators/impls/MarkOperatorFactoryChain"; +import MockMarkKeyRepository from "../../mock/MockMarkKeyRepository"; +import EnableSetMarkOperator from "../../../../src/content/operators/impls/EnableSetMarkOperator"; +import EnableJumpMarkOperator from "../../../../src/content/operators/impls/EnableJumpMarkOperator"; + +describe("MarkOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new MarkOperatorFactoryChain(new MockMarkKeyRepository()); + expect( + sut.create({ type: operations.MARK_SET_PREFIX }, 0) + ).to.be.instanceOf(EnableSetMarkOperator); + expect( + sut.create({ type: operations.MARK_JUMP_PREFIX }, 0) + ).to.be.instanceOf(EnableJumpMarkOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/PageScrollOperator.test.ts b/test/content/operators/impls/PageScrollOperator.test.ts new file mode 100644 index 0000000..80c9185 --- /dev/null +++ b/test/content/operators/impls/PageScrollOperator.test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import PageScrollOperator from "../../../../src/content/operators/impls/PageScrollOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("PageScrollOperator", () => { + describe("#run", () => { + it("scroll by a page", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new PageScrollOperator(presenter, settingRepository, 1); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 1, y: 0 }); + }); + + it("scroll by a page with repeats", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new PageScrollOperator(presenter, settingRepository, 5); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 5, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/PasteOperator.test.ts b/test/content/operators/impls/PasteOperator.test.ts new file mode 100644 index 0000000..8a3a374 --- /dev/null +++ b/test/content/operators/impls/PasteOperator.test.ts @@ -0,0 +1,51 @@ +import sinon from "sinon"; +import PasteOperator from "../../../../src/content/operators/impls/PasteOperator"; +import MockClipboardRepository from "../../mock/MockClipboardRepository"; +import MockSettingRepository from "../../mock/MockSettingRepository"; +import MockOperationClient from "../../mock/MockOperationClient"; + +describe("PasteOperator", () => { + describe("#run", () => { + it("open a search url", async () => { + const clipboardRepository = new MockClipboardRepository("apple"); + const settingRepository = new MockSettingRepository(); + const operationClient = new MockOperationClient(); + const mockOperationClient = sinon + .mock(operationClient) + .expects("internalOpenUrl") + .withArgs("https://google.com/search?q=apple"); + const sut = new PasteOperator( + clipboardRepository, + settingRepository, + operationClient, + false + ); + + await sut.run(); + + mockOperationClient.verify(); + }); + + it("open a url", async () => { + const clipboardRepository = new MockClipboardRepository( + "https://example.com/" + ); + const settingRepository = new MockSettingRepository(); + const operationClient = new MockOperationClient(); + const mockOperationClient = sinon + .mock(operationClient) + .expects("internalOpenUrl") + .withArgs("https://example.com/"); + const sut = new PasteOperator( + clipboardRepository, + settingRepository, + operationClient, + false + ); + + await sut.run(); + + mockOperationClient.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollOperatorFactoryChain.test.ts b/test/content/operators/impls/ScrollOperatorFactoryChain.test.ts new file mode 100644 index 0000000..08034cb --- /dev/null +++ b/test/content/operators/impls/ScrollOperatorFactoryChain.test.ts @@ -0,0 +1,46 @@ +import { expect } from "chai"; +import ScrollOperatorFactoryChain from "../../../../src/content/operators/impls/ScrollOperatorFactoryChain"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; +import HorizontalScrollOperator from "../../../../src/content/operators/impls/HorizontalScrollOperator"; +import VerticalScrollOperator from "../../../../src/content/operators/impls/VerticalScrollOperator"; +import PageScrollOperator from "../../../../src/content/operators/impls/PageScrollOperator"; +import ScrollToTopOperator from "../../../../src/content/operators/impls/ScrollToTopOperator"; +import ScrollToBottomOperator from "../../../../src/content/operators/impls/ScrollToBottomOperator"; +import ScrollToHomeOperator from "../../../../src/content/operators/impls/ScrollToHomeOperator"; +import ScrollToEndOperator from "../../../../src/content/operators/impls/ScrollToEndOperator"; +import * as operations from "../../../../src/shared/operations"; + +describe("ScrollOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new ScrollOperatorFactoryChain( + new MockScrollPresenter(), + new MockSettingRepository() + ); + expect( + sut.create({ type: operations.SCROLL_HORIZONALLY, count: 10 }, 0) + ).to.be.instanceOf(HorizontalScrollOperator); + expect( + sut.create({ type: operations.SCROLL_VERTICALLY, count: 10 }, 0) + ).to.be.instanceOf(VerticalScrollOperator); + expect( + sut.create({ type: operations.SCROLL_PAGES, count: 10 }, 0) + ).to.be.instanceOf(PageScrollOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.instanceOf( + ScrollToTopOperator + ); + expect( + sut.create({ type: operations.SCROLL_BOTTOM }, 0) + ).to.be.instanceOf(ScrollToBottomOperator); + expect(sut.create({ type: operations.SCROLL_HOME }, 0)).to.be.instanceOf( + ScrollToHomeOperator + ); + expect(sut.create({ type: operations.SCROLL_END }, 0)).to.be.instanceOf( + ScrollToEndOperator + ); + expect(sut.create({ type: operations.PAGE_HOME, newTab: false }, 0)).to.be + .null; + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToBottomOperator.test.ts b/test/content/operators/impls/ScrollToBottomOperator.test.ts new file mode 100644 index 0000000..500c8f2 --- /dev/null +++ b/test/content/operators/impls/ScrollToBottomOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToBottomOperator from "../../../../src/content/operators/impls/ScrollToBottomOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToBottomOperator", () => { + describe("#run", () => { + it("scroll to bottom", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToBottomOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: Infinity }); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToEndOperator.test.ts b/test/content/operators/impls/ScrollToEndOperator.test.ts new file mode 100644 index 0000000..0c98c8d --- /dev/null +++ b/test/content/operators/impls/ScrollToEndOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToEndOperator from "../../../../src/content/operators/impls/ScrollToEndOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToEndOperator", () => { + describe("#run", () => { + it("scroll to rightmost", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToEndOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: Infinity, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToHomeOperator.test.ts b/test/content/operators/impls/ScrollToHomeOperator.test.ts new file mode 100644 index 0000000..f8614d2 --- /dev/null +++ b/test/content/operators/impls/ScrollToHomeOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToHomeOperator from "../../../../src/content/operators/impls/ScrollToHomeOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToHomeOperator", () => { + describe("#run", () => { + it("scroll to leftmost", async () => { + const presenter = new MockScrollPresenter(10, 10); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToHomeOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: 10 }); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToTopOperator.test.ts b/test/content/operators/impls/ScrollToTopOperator.test.ts new file mode 100644 index 0000000..25a84ba --- /dev/null +++ b/test/content/operators/impls/ScrollToTopOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToTopOperator from "../../../../src/content/operators/impls/ScrollToTopOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToTopOperator", () => { + describe("#run", () => { + it("scroll to top", async () => { + const presenter = new MockScrollPresenter(10, 10); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToTopOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 10, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/StartFollowOperator.test.ts b/test/content/operators/impls/StartFollowOperator.test.ts new file mode 100644 index 0000000..8f9bd2d --- /dev/null +++ b/test/content/operators/impls/StartFollowOperator.test.ts @@ -0,0 +1,20 @@ +import sinon from "sinon"; +import StartFollowOperator from "../../../../src/content/operators/impls/StartFollowOperator"; +import MockFollowMasterClient from "../../mock/MockFollowMasterClient"; + +describe("StartFollowOperator", () => { + describe("#run", () => { + it("starts following links", async () => { + const client = new MockFollowMasterClient(); + const mock = sinon + .mock(client) + .expects("startFollow") + .withArgs(true, false); + const sut = new StartFollowOperator(client, true, false); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/ToggleAddonOperator.test.ts b/test/content/operators/impls/ToggleAddonOperator.test.ts new file mode 100644 index 0000000..6026eb1 --- /dev/null +++ b/test/content/operators/impls/ToggleAddonOperator.test.ts @@ -0,0 +1,24 @@ +import { expect } from "chai"; +import ToggleAddonOperator from "../../../../src/content/operators/impls/ToggleAddonOperator"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("ToggleAddonOperator", () => { + describe("#run", () => { + it("toggles addon-enabled state", async () => { + const client = new MockAddonIndicatorClient(true); + const repository = new MockAddonEnabledRepository(true); + const sut = new ToggleAddonOperator(client, repository); + + await sut.run(); + + expect(client.enabled).to.be.false; + expect(repository.enabled).to.be.false; + + await sut.run(); + + expect(client.enabled).to.be.true; + expect(repository.enabled).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/VerticalScrollOperator.test.ts b/test/content/operators/impls/VerticalScrollOperator.test.ts new file mode 100644 index 0000000..05b15d2 --- /dev/null +++ b/test/content/operators/impls/VerticalScrollOperator.test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import VerticalScrollOperator from "../../../../src/content/operators/impls/VerticalScrollOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("VerticalScrollOperator", () => { + describe("#run", () => { + it("scroll vertically", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new VerticalScrollOperator(presenter, settingRepository, 1); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: 1 }); + }); + + it("scroll vertically with repeats", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new VerticalScrollOperator(presenter, settingRepository, 5); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: 5 }); + }); + }); +}); diff --git a/test/content/operators/impls/YankURLOperator.test.ts b/test/content/operators/impls/YankURLOperator.test.ts new file mode 100644 index 0000000..46e3d06 --- /dev/null +++ b/test/content/operators/impls/YankURLOperator.test.ts @@ -0,0 +1,26 @@ +import { expect } from "chai"; +import MockClipboardRepository from "../../mock/MockClipboardRepository"; +import YankURLOperator from "../../../../src/content/operators/impls/YankURLOperator"; +import MockURLRepository from "../../mock/MockURLRepository"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("YankOperation", () => { + describe("#run", () => { + it("copy current URL", async () => { + const clipboardRepository = new MockClipboardRepository(); + const consoleClient = new MockConsoleClient(); + const urlRepository = new MockURLRepository("https://example.com/"); + const sut = new YankURLOperator( + clipboardRepository, + consoleClient, + urlRepository + ); + + await sut.run(); + + expect(clipboardRepository.read()).to.equal("https://example.com/"); + expect(consoleClient.text).to.equal("Yanked https://example.com/"); + expect(consoleClient.isError).to.be.false; + }); + }); +}); -- cgit v1.2.3 From dcb09f7c74ff3d396431e423b0be6572c3f98955 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 29 Nov 2020 14:05:30 +0900 Subject: Remove unused usecases --- src/content/usecases/ClipboardUseCase.ts | 34 --------- src/content/usecases/FindSlaveUseCase.ts | 17 ----- src/content/usecases/FocusUseCase.ts | 11 --- src/content/usecases/MarkKeyUseCase.ts | 8 --- src/content/usecases/ScrollUseCase.ts | 51 -------------- test/content/usecases/ClipboardUseCase.test.ts | 95 -------------------------- 6 files changed, 216 deletions(-) delete mode 100644 src/content/usecases/ClipboardUseCase.ts delete mode 100644 src/content/usecases/FindSlaveUseCase.ts delete mode 100644 src/content/usecases/FocusUseCase.ts delete mode 100644 src/content/usecases/ScrollUseCase.ts delete mode 100644 test/content/usecases/ClipboardUseCase.test.ts (limited to 'test') diff --git a/src/content/usecases/ClipboardUseCase.ts b/src/content/usecases/ClipboardUseCase.ts deleted file mode 100644 index 875fc11..0000000 --- a/src/content/usecases/ClipboardUseCase.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { injectable, inject } from "tsyringe"; -import * as urls from "../../shared/urls"; -import ClipboardRepository from "../repositories/ClipboardRepository"; -import SettingRepository from "../repositories/SettingRepository"; -import ConsoleClient from "../client/ConsoleClient"; -import OperationClient from "../client/OperationClient"; - -@injectable() -export default class ClipboardUseCase { - constructor( - @inject("ClipboardRepository") private repository: ClipboardRepository, - @inject("SettingRepository") private settingRepository: SettingRepository, - @inject("ConsoleClient") private consoleClient: ConsoleClient, - @inject("OperationClient") private operationClinet: OperationClient - ) {} - - async yankCurrentURL(): Promise { - const url = window.location.href; - this.repository.write(url); - await this.consoleClient.info("Yanked " + url); - return Promise.resolve(url); - } - - async openOrSearch(newTab: boolean): Promise { - const search = this.settingRepository.get().search; - const text = this.repository.read(); - const url = urls.searchUrl(text, search); - - // TODO: Repeat pasting from clipboard instead of opening a certain url. - // 'Repeat last' command is implemented in the background script and cannot - // access to clipboard until Firefox 63. - await this.operationClinet.internalOpenUrl(url, newTab); - } -} diff --git a/src/content/usecases/FindSlaveUseCase.ts b/src/content/usecases/FindSlaveUseCase.ts deleted file mode 100644 index 3b8c4b4..0000000 --- a/src/content/usecases/FindSlaveUseCase.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { injectable, inject } from "tsyringe"; -import FindMasterClient from "../client/FindMasterClient"; - -@injectable() -export default class FindSlaveUseCase { - constructor( - @inject("FindMasterClient") private findMasterClient: FindMasterClient - ) {} - - findNext() { - this.findMasterClient.findNext(); - } - - findPrev() { - this.findMasterClient.findPrev(); - } -} diff --git a/src/content/usecases/FocusUseCase.ts b/src/content/usecases/FocusUseCase.ts deleted file mode 100644 index 8c62003..0000000 --- a/src/content/usecases/FocusUseCase.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { injectable, inject } from "tsyringe"; -import FocusPresenter from "../presenters/FocusPresenter"; - -@injectable() -export default class FocusUseCases { - constructor(@inject("FocusPresenter") private presenter: FocusPresenter) {} - - focusFirstInput() { - this.presenter.focusFirstElement(); - } -} diff --git a/src/content/usecases/MarkKeyUseCase.ts b/src/content/usecases/MarkKeyUseCase.ts index b807c74..61ed135 100644 --- a/src/content/usecases/MarkKeyUseCase.ts +++ b/src/content/usecases/MarkKeyUseCase.ts @@ -15,18 +15,10 @@ export default class MarkKeyUseCase { return this.repository.isJumpMode(); } - enableSetMode(): void { - this.repository.enableSetMode(); - } - disableSetMode(): void { this.repository.disabeSetMode(); } - enableJumpMode(): void { - this.repository.enableJumpMode(); - } - disableJumpMode(): void { this.repository.disabeJumpMode(); } diff --git a/src/content/usecases/ScrollUseCase.ts b/src/content/usecases/ScrollUseCase.ts deleted file mode 100644 index 319c8b4..0000000 --- a/src/content/usecases/ScrollUseCase.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { injectable, inject } from "tsyringe"; -import ScrollPresenter from "../presenters/ScrollPresenter"; -import SettingRepository from "../repositories/SettingRepository"; - -@injectable() -export default class ScrollUseCase { - constructor( - @inject("ScrollPresenter") private presenter: ScrollPresenter, - @inject("SettingRepository") private settingRepository: SettingRepository - ) {} - - scrollVertically(count: number): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollVertically(count, smooth); - } - - scrollHorizonally(count: number): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollHorizonally(count, smooth); - } - - scrollPages(count: number): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollPages(count, smooth); - } - - scrollToTop(): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToTop(smooth); - } - - scrollToBottom(): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToBottom(smooth); - } - - scrollToHome(): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToHome(smooth); - } - - scrollToEnd(): void { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToEnd(smooth); - } - - private getSmoothScroll(): boolean { - const settings = this.settingRepository.get(); - return settings.properties.smoothscroll; - } -} diff --git a/test/content/usecases/ClipboardUseCase.test.ts b/test/content/usecases/ClipboardUseCase.test.ts deleted file mode 100644 index 5de3e69..0000000 --- a/test/content/usecases/ClipboardUseCase.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import ClipboardRepository from "../../../src/content/repositories/ClipboardRepository"; -import { SettingRepositoryImpl } from "../../../src/content/repositories/SettingRepository"; -import ClipboardUseCase from "../../../src/content/usecases/ClipboardUseCase"; -import OperationClient from "../../../src/content/client/OperationClient"; -import ConsoleClient from "../../../src/content/client/ConsoleClient"; - -import * as sinon from "sinon"; -import { expect } from "chai"; -import { Operation } from "../../../src/shared/operations"; - -describe("ClipboardUseCase", () => { - let clipboardRepository: ClipboardRepository; - - let operationClient: OperationClient; - - let consoleClient: ConsoleClient; - - let sut: ClipboardUseCase; - - beforeEach(() => { - clipboardRepository = new (class implements ClipboardRepository { - read(): string { - return ""; - } - write(_text: string) {} - })(); - operationClient = new (class implements OperationClient { - execBackgroundOp(_repeat: number, _op: Operation): Promise { - return Promise.resolve(); - } - internalOpenUrl( - _url: string, - _newTab?: boolean, - _background?: boolean - ): Promise { - return Promise.resolve(); - } - })(); - consoleClient = new (class implements ConsoleClient { - error(_text: string): Promise { - return Promise.resolve(); - } - info(_text: string): Promise { - return Promise.resolve(); - } - })(); - - sut = new ClipboardUseCase( - clipboardRepository, - new SettingRepositoryImpl(), - consoleClient, - operationClient - ); - }); - - describe("#yankCurrentURL", () => { - it("yanks current url", async () => { - const href = window.location.href; - const mockRepository = sinon.mock(clipboardRepository); - mockRepository.expects("write").withArgs(href); - const mockConsoleClient = sinon.mock(consoleClient); - mockConsoleClient.expects("info").withArgs("Yanked " + href); - - const yanked = await sut.yankCurrentURL(); - - expect(yanked).to.equal(href); - mockRepository.verify(); - mockConsoleClient.verify(); - }); - }); - - describe("#openOrSearch", () => { - it("opens url from the clipboard", async () => { - const url = "https://github.com/ueokande/vim-vixen"; - sinon.stub(clipboardRepository, "read").returns(url); - const mockOperationClient = sinon.mock(operationClient); - mockOperationClient.expects("internalOpenUrl").withArgs(url, true); - - await sut.openOrSearch(true); - - mockOperationClient.verify(); - }); - - it("opens search results from the clipboard", async () => { - const url = "https://google.com/search?q=banana"; - sinon.stub(clipboardRepository, "read").returns("banana"); - const mockOperationClient = sinon.mock(operationClient); - mockOperationClient.expects("internalOpenUrl").withArgs(url, true); - - await sut.openOrSearch(true); - - mockOperationClient.verify(); - }); - }); -}); -- cgit v1.2.3 From ca804b1b335df0e7a316d12ed9246beec55ff7f2 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 2 Dec 2020 22:40:10 +0900 Subject: Make background operator as an operator --- src/background/clients/NavigateClient.ts | 14 +++-- src/background/di.ts | 12 +++++ src/background/infrastructures/ConsoleClient.ts | 14 ++++- .../operators/impls/CommandOperatorFactoryChain.ts | 1 + .../impls/InternalOperatorFactoryChain.ts | 1 + .../impls/NavigateOperatorFactoryChain.ts | 2 + .../operators/impls/RepeatOperatorFactoryChain.ts | 1 + .../operators/impls/ResetZoomOperator.ts | 7 +-- .../operators/impls/ShowAddBookmarkOperator.ts | 2 +- src/background/operators/impls/ZoomInOperator.ts | 6 +-- .../operators/impls/ZoomOperatorFactoryChain.ts | 15 +++--- src/background/operators/impls/ZoomOutOperator.ts | 6 +-- .../repositories/BrowserSettingRepository.ts | 6 ++- src/background/repositories/RepeatRepository.ts | 8 ++- src/background/usecases/CommandUseCase.ts | 18 ++++--- src/background/usecases/ConsoleUseCase.ts | 6 ++- src/background/usecases/FindUseCase.ts | 8 +-- src/background/usecases/MarkUseCase.ts | 12 +++-- src/background/usecases/NavigateUseCase.ts | 6 ++- src/background/usecases/RepeatUseCase.ts | 7 ++- src/background/usecases/TabUseCase.ts | 8 +-- src/background/usecases/ZoomPresenter.ts | 60 ++++++++++++++++++++++ test/background/usecases/NavigateUseCase.test.ts | 6 ++- 23 files changed, 177 insertions(+), 49 deletions(-) create mode 100644 src/background/usecases/ZoomPresenter.ts (limited to 'test') diff --git a/src/background/clients/NavigateClient.ts b/src/background/clients/NavigateClient.ts index 40ceb45..af8688e 100644 --- a/src/background/clients/NavigateClient.ts +++ b/src/background/clients/NavigateClient.ts @@ -1,8 +1,16 @@ -import { injectable } from "tsyringe"; import * as messages from "../../shared/messages"; -@injectable() -export default class NavigateClient { +export default interface NavigateClient { + historyNext(tabId: number): Promise; + + historyPrev(tabId: number): Promise; + + linkNext(tabId: number): Promise; + + linkPrev(tabId: number): Promise; +} + +export class NavigateClientImpl implements NavigateClient { async historyNext(tabId: number): Promise { await browser.tabs.sendMessage(tabId, { type: messages.NAVIGATE_HISTORY_NEXT, diff --git a/src/background/di.ts b/src/background/di.ts index 44bf427..8623f95 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -12,6 +12,11 @@ import BookmarkRepositoryImpl from "./completion/impl/BookmarkRepositoryImpl"; import TabRepositoryImpl from "./completion/impl/TabRepositoryImpl"; import { TabPresenterImpl } from "./presenters/TabPresenter"; import { OperatorFactoryImpl } from "./operators/impls/OperatorFactoryImpl"; +import { NavigateClientImpl } from "./clients/NavigateClient"; +import { ConsoleClientImpl } from "./infrastructures/ConsoleClient"; +import { BrowserSettingRepositoryImpl } from "./repositories/BrowserSettingRepository"; +import { RepeatRepositoryImpl } from "./repositories/RepeatRepository"; +import { ZoomPresenterImpl } from "./usecases/ZoomPresenter"; container.register("LocalSettingRepository", { useValue: LocalSettingRepository, @@ -25,6 +30,13 @@ container.register("CachedSettingRepository", { container.register("Notifier", { useClass: NotifierImpl }); container.register("HistoryRepository", { useClass: HistoryRepositoryImpl }); container.register("BookmarkRepository", { useClass: BookmarkRepositoryImpl }); +container.register("BrowserSettingRepository", { + useClass: BrowserSettingRepositoryImpl, +}); +container.register("RepeatRepository", { useClass: RepeatRepositoryImpl }); container.register("TabRepository", { useClass: TabRepositoryImpl }); +container.register("ZoomPresenter", { useClass: ZoomPresenterImpl }); container.register("TabPresenter", { useClass: TabPresenterImpl }); +container.register("NavigateClient", { useClass: NavigateClientImpl }); +container.register("ConsoleClient", { useClass: ConsoleClientImpl }); container.register("OperatorFactory", { useClass: OperatorFactoryImpl }); diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts index 8d0af89..2a1df5b 100644 --- a/src/background/infrastructures/ConsoleClient.ts +++ b/src/background/infrastructures/ConsoleClient.ts @@ -1,8 +1,20 @@ import { injectable } from "tsyringe"; import * as messages from "../../shared/messages"; +export default interface ConsoleClient { + showCommand(tabId: number, command: string): Promise; + + showFind(tabId: number): Promise; + + showInfo(tabId: number, message: string): Promise; + + showError(tabId: number, message: string): Promise; + + hide(tabId: number): Promise; +} + @injectable() -export default class ConsoleClient { +export class ConsoleClientImpl implements ConsoleClient { showCommand(tabId: number, command: string): Promise { return browser.tabs.sendMessage(tabId, { type: messages.CONSOLE_SHOW_COMMAND, diff --git a/src/background/operators/impls/CommandOperatorFactoryChain.ts b/src/background/operators/impls/CommandOperatorFactoryChain.ts index 7432153..680a384 100644 --- a/src/background/operators/impls/CommandOperatorFactoryChain.ts +++ b/src/background/operators/impls/CommandOperatorFactoryChain.ts @@ -18,6 +18,7 @@ export default class CommandOperatorFactoryChain constructor( @inject("TabPresenter") private readonly tabPresenter: TabPresenter, + @inject("ConsoleClient") private readonly consoleClient: ConsoleClient ) {} diff --git a/src/background/operators/impls/InternalOperatorFactoryChain.ts b/src/background/operators/impls/InternalOperatorFactoryChain.ts index 607dbfa..fd3e010 100644 --- a/src/background/operators/impls/InternalOperatorFactoryChain.ts +++ b/src/background/operators/impls/InternalOperatorFactoryChain.ts @@ -15,6 +15,7 @@ export default class InternalOperatorFactoryChain private readonly windowPresenter: WindowPresenter, @inject("TabPresenter") private readonly tabPresenter: TabPresenter, + @inject("ConsoleClient") private readonly consoleClient: ConsoleClient ) {} diff --git a/src/background/operators/impls/NavigateOperatorFactoryChain.ts b/src/background/operators/impls/NavigateOperatorFactoryChain.ts index d9b1619..618db45 100644 --- a/src/background/operators/impls/NavigateOperatorFactoryChain.ts +++ b/src/background/operators/impls/NavigateOperatorFactoryChain.ts @@ -20,7 +20,9 @@ export default class NavigateOperatorFactoryChain constructor( @inject("TabPresenter") private readonly tabPresenter: TabPresenter, + @inject("NavigateClient") private readonly navigateClient: NavigateClient, + @inject("BrowserSettingRepository") private readonly browserSettingRepository: BrowserSettingRepository ) {} diff --git a/src/background/operators/impls/RepeatOperatorFactoryChain.ts b/src/background/operators/impls/RepeatOperatorFactoryChain.ts index 9d67b75..5038d48 100644 --- a/src/background/operators/impls/RepeatOperatorFactoryChain.ts +++ b/src/background/operators/impls/RepeatOperatorFactoryChain.ts @@ -10,6 +10,7 @@ import * as operations from "../../../shared/operations"; export default class RepeatOperatorFactoryChain implements OperatorFactoryChain { constructor( + @inject("RepeatRepository") private readonly repeatRepository: RepeatRepository, @inject("OperatorFactory") private readonly operatorFactory: OperatorFactory diff --git a/src/background/operators/impls/ResetZoomOperator.ts b/src/background/operators/impls/ResetZoomOperator.ts index 66cf245..48db1d5 100644 --- a/src/background/operators/impls/ResetZoomOperator.ts +++ b/src/background/operators/impls/ResetZoomOperator.ts @@ -1,9 +1,10 @@ import Operator from "../Operator"; -import ZoomUseCase from "../../usecases/ZoomUseCase"; +import ZoomPresenter from "../../usecases/ZoomPresenter"; export default class ResetZoomOperator implements Operator { - constructor(private readonly zoomUseCase: ZoomUseCase) {} + constructor(private readonly zoomPresenter: ZoomPresenter) {} + run(): Promise { - return this.zoomUseCase.zoomNutoral(); + return this.zoomPresenter.resetZoom(); } } diff --git a/src/background/operators/impls/ShowAddBookmarkOperator.ts b/src/background/operators/impls/ShowAddBookmarkOperator.ts index a1752eb..cce4879 100644 --- a/src/background/operators/impls/ShowAddBookmarkOperator.ts +++ b/src/background/operators/impls/ShowAddBookmarkOperator.ts @@ -11,7 +11,7 @@ export default class ShowAddBookmarkOperator implements Operator { async run(): Promise { const tab = await this.tabPresenter.getCurrent(); - let command = "addookmark "; + let command = "addbookmark "; if (this.alter) { command += tab.title || ""; } diff --git a/src/background/operators/impls/ZoomInOperator.ts b/src/background/operators/impls/ZoomInOperator.ts index 0c44c6f..9ed1861 100644 --- a/src/background/operators/impls/ZoomInOperator.ts +++ b/src/background/operators/impls/ZoomInOperator.ts @@ -1,10 +1,10 @@ import Operator from "../Operator"; -import ZoomUseCase from "../../usecases/ZoomUseCase"; +import ZoomPresenter from "../../usecases/ZoomPresenter"; export default class ZoomInOperator implements Operator { - constructor(private readonly zoomUseCase: ZoomUseCase) {} + constructor(private readonly zoomPresenter: ZoomPresenter) {} run(): Promise { - return this.zoomUseCase.zoomIn(); + return this.zoomPresenter.zoomIn(); } } diff --git a/src/background/operators/impls/ZoomOperatorFactoryChain.ts b/src/background/operators/impls/ZoomOperatorFactoryChain.ts index b8858ab..ebcf2a5 100644 --- a/src/background/operators/impls/ZoomOperatorFactoryChain.ts +++ b/src/background/operators/impls/ZoomOperatorFactoryChain.ts @@ -1,24 +1,27 @@ -import { injectable } from "tsyringe"; +import { inject, injectable } from "tsyringe"; import Operator from "../Operator"; import OperatorFactoryChain from "../OperatorFactoryChain"; import ZoomInOperator from "./ZoomInOperator"; import ZoomOutOperator from "./ZoomOutOperator"; import ResetZoomOperator from "./ResetZoomOperator"; -import ZoomUseCase from "../../usecases/ZoomUseCase"; +import ZoomPresenter from "../../usecases/ZoomPresenter"; import * as operations from "../../../shared/operations"; @injectable() export default class ZoomOperatorFactoryChain implements OperatorFactoryChain { - constructor(private readonly zoomUseCase: ZoomUseCase) {} + constructor( + @inject("ZoomPresenter") + private readonly zoomPresenter: ZoomPresenter + ) {} create(op: operations.Operation): Operator | null { switch (op.type) { case operations.ZOOM_IN: - return new ZoomInOperator(this.zoomUseCase); + return new ZoomInOperator(this.zoomPresenter); case operations.ZOOM_OUT: - return new ZoomOutOperator(this.zoomUseCase); + return new ZoomOutOperator(this.zoomPresenter); case operations.ZOOM_NEUTRAL: - return new ResetZoomOperator(this.zoomUseCase); + return new ResetZoomOperator(this.zoomPresenter); } return null; } diff --git a/src/background/operators/impls/ZoomOutOperator.ts b/src/background/operators/impls/ZoomOutOperator.ts index 7f9cb6b..35f5d3d 100644 --- a/src/background/operators/impls/ZoomOutOperator.ts +++ b/src/background/operators/impls/ZoomOutOperator.ts @@ -1,10 +1,10 @@ import Operator from "../Operator"; -import ZoomUseCase from "../../usecases/ZoomUseCase"; +import ZoomPresenter from "../../usecases/ZoomPresenter"; export default class ZoomOutOperator implements Operator { - constructor(private readonly zoomUseCase: ZoomUseCase) {} + constructor(private readonly zoomPresenter: ZoomPresenter) {} run(): Promise { - return this.zoomUseCase.zoomOut(); + return this.zoomPresenter.zoomOut(); } } diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts index e24874b..1dde190 100644 --- a/src/background/repositories/BrowserSettingRepository.ts +++ b/src/background/repositories/BrowserSettingRepository.ts @@ -1,8 +1,12 @@ import { injectable } from "tsyringe"; import * as urls from "../../shared/urls"; +export default interface BrowserSettingRepository { + getHomepageUrls(): Promise; +} + @injectable() -export default class BrowserSettingRepository { +export class BrowserSettingRepositoryImpl implements BrowserSettingRepository { async getHomepageUrls(): Promise { const { value } = await browser.browserSettings.homepageOverride.get({}); return value.split("|").map(urls.normalizeUrl); diff --git a/src/background/repositories/RepeatRepository.ts b/src/background/repositories/RepeatRepository.ts index e3ab43d..00098d3 100644 --- a/src/background/repositories/RepeatRepository.ts +++ b/src/background/repositories/RepeatRepository.ts @@ -4,8 +4,14 @@ import MemoryStorage from "../infrastructures/MemoryStorage"; const REPEAT_KEY = "repeat"; +export default interface RepeatRepository { + getLastOperation(): Operation | undefined; + + setLastOperation(op: Operation): void; +} + @injectable() -export default class RepeatRepository { +export class RepeatRepositoryImpl implements RepeatRepository { private cache: MemoryStorage; constructor() { diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts index 811ec77..69ef3ea 100644 --- a/src/background/usecases/CommandUseCase.ts +++ b/src/background/usecases/CommandUseCase.ts @@ -14,15 +14,17 @@ import RepeatUseCase from "../usecases/RepeatUseCase"; @injectable() export default class CommandIndicator { constructor( - @inject("TabPresenter") private tabPresenter: TabPresenter, - private windowPresenter: WindowPresenter, - private helpPresenter: HelpPresenter, + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + private readonly windowPresenter: WindowPresenter, + private readonly helpPresenter: HelpPresenter, @inject("CachedSettingRepository") - private cachedSettingRepository: CachedSettingRepository, - private bookmarkRepository: BookmarkRepository, - private consoleClient: ConsoleClient, - private contentMessageClient: ContentMessageClient, - private repeatUseCase: RepeatUseCase + private readonly cachedSettingRepository: CachedSettingRepository, + private readonly bookmarkRepository: BookmarkRepository, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient, + private readonly contentMessageClient: ContentMessageClient, + private readonly repeatUseCase: RepeatUseCase ) {} async open(keywords: string): Promise { diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts index 195c70f..4adba65 100644 --- a/src/background/usecases/ConsoleUseCase.ts +++ b/src/background/usecases/ConsoleUseCase.ts @@ -5,8 +5,10 @@ import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class ConsoleUseCase { constructor( - @inject("TabPresenter") private tabPresenter: TabPresenter, - private consoleClient: ConsoleClient + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient ) {} async showCommand(): Promise { diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts index facc461..404fb48 100644 --- a/src/background/usecases/FindUseCase.ts +++ b/src/background/usecases/FindUseCase.ts @@ -6,9 +6,11 @@ import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class FindUseCase { constructor( - @inject("TabPresenter") private tabPresenter: TabPresenter, - private findRepository: FindRepository, - private consoleClient: ConsoleClient + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + private readonly findRepository: FindRepository, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient ) {} getKeyword(): Promise { diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts index 9da9a21..57e04b4 100644 --- a/src/background/usecases/MarkUseCase.ts +++ b/src/background/usecases/MarkUseCase.ts @@ -1,16 +1,18 @@ import { inject, injectable } from "tsyringe"; import TabPresenter from "../presenters/TabPresenter"; import MarkRepository from "../repositories/MarkRepository"; -import ConsoleClient from "../infrastructures/ConsoleClient"; import ContentMessageClient from "../infrastructures/ContentMessageClient"; +import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class MarkUseCase { constructor( - @inject("TabPresenter") private tabPresenter: TabPresenter, - private markRepository: MarkRepository, - private consoleClient: ConsoleClient, - private contentMessageClient: ContentMessageClient + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + private readonly markRepository: MarkRepository, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient, + private readonly contentMessageClient: ContentMessageClient ) {} async setGlobal(key: string, x: number, y: number): Promise { diff --git a/src/background/usecases/NavigateUseCase.ts b/src/background/usecases/NavigateUseCase.ts index 974606c..29e629a 100644 --- a/src/background/usecases/NavigateUseCase.ts +++ b/src/background/usecases/NavigateUseCase.ts @@ -5,8 +5,10 @@ import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class NavigateUseCase { constructor( - @inject("TabPresenter") private tabPresenter: TabPresenter, - private navigateClient: NavigateClient + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + @inject("NavigateClient") + private readonly navigateClient: NavigateClient ) {} async openHistoryNext(): Promise { diff --git a/src/background/usecases/RepeatUseCase.ts b/src/background/usecases/RepeatUseCase.ts index d7235ee..992e76b 100644 --- a/src/background/usecases/RepeatUseCase.ts +++ b/src/background/usecases/RepeatUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from "tsyringe"; +import { inject, injectable } from "tsyringe"; import * as operations from "../../shared/operations"; import RepeatRepository from "../repositories/RepeatRepository"; @@ -6,7 +6,10 @@ type Operation = operations.Operation; @injectable() export default class RepeatUseCase { - constructor(private repeatRepository: RepeatRepository) {} + constructor( + @inject("RepeatRepository") + private readonly repeatRepository: RepeatRepository + ) {} storeLastOperation(op: Operation): void { this.repeatRepository.setLastOperation(op); diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts index 1439107..900c305 100644 --- a/src/background/usecases/TabUseCase.ts +++ b/src/background/usecases/TabUseCase.ts @@ -6,9 +6,11 @@ import BrowserSettingRepository from "../repositories/BrowserSettingRepository"; @injectable() export default class TabUseCase { constructor( - @inject("TabPresenter") private tabPresenter: TabPresenter, - private windowPresenter: WindowPresenter, - private browserSettingRepository: BrowserSettingRepository + @inject("TabPresenter") + private readonly tabPresenter: TabPresenter, + private readonly windowPresenter: WindowPresenter, + @inject("BrowserSettingRepository") + private readonly browserSettingRepository: BrowserSettingRepository ) {} async close(force: boolean, selectLeft = false): Promise { diff --git a/src/background/usecases/ZoomPresenter.ts b/src/background/usecases/ZoomPresenter.ts new file mode 100644 index 0000000..5a3c64d --- /dev/null +++ b/src/background/usecases/ZoomPresenter.ts @@ -0,0 +1,60 @@ +const ZOOM_SETTINGS = [ + 0.33, + 0.5, + 0.66, + 0.75, + 0.8, + 0.9, + 1.0, + 1.1, + 1.25, + 1.5, + 1.75, + 2.0, + 2.5, + 3.0, +] as const; + +export default interface ZoomPresenter { + zoomIn(): Promise; + zoomOut(): Promise; + resetZoom(): Promise; +} + +export class ZoomPresenterImpl implements ZoomPresenter { + async zoomIn(): Promise { + const tab = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + const tabId = tab[0].id as number; + const current = await browser.tabs.getZoom(tabId); + const factor = ZOOM_SETTINGS.find((f) => f > current); + if (factor) { + return browser.tabs.setZoom(tabId, factor); + } + } + + async zoomOut(): Promise { + const tab = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + const tabId = tab[0].id as number; + const current = await browser.tabs.getZoom(tabId); + const factor = ZOOM_SETTINGS.slice(0) + .reverse() + .find((f) => f < current); + if (factor) { + return browser.tabs.setZoom(tabId, factor); + } + } + + async resetZoom(): Promise { + const tab = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + return browser.tabs.setZoom(tab[0].id, 1); + } +} diff --git a/test/background/usecases/NavigateUseCase.test.ts b/test/background/usecases/NavigateUseCase.test.ts index 086d6cd..f1b94a7 100644 --- a/test/background/usecases/NavigateUseCase.test.ts +++ b/test/background/usecases/NavigateUseCase.test.ts @@ -1,7 +1,9 @@ import "reflect-metadata"; import TabPresenter from "../../../src/background/presenters/TabPresenter"; import NavigateUseCase from "../../../src/background/usecases/NavigateUseCase"; -import NavigateClient from "../../../src/background/clients/NavigateClient"; +import NavigateClient, { + NavigateClientImpl, +} from "../../../src/background/clients/NavigateClient"; import * as sinon from "sinon"; class MockTabPresenter implements TabPresenter { @@ -78,7 +80,7 @@ describe("NavigateUseCase", () => { beforeEach(() => { tabPresenter = new MockTabPresenter(); - navigateClient = new NavigateClient(); + navigateClient = new NavigateClientImpl(); sut = new NavigateUseCase(tabPresenter, navigateClient); }); -- cgit v1.2.3 From 8bbc3d9d159237f280c3e952cd1cb124601ed6d6 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Thu, 3 Dec 2020 23:15:24 +0900 Subject: Add operator tests --- .../mock/MockBrowserSettingRepository.ts | 10 ++ test/background/mock/MockConsoleClient.ts | 23 +++ test/background/mock/MockNavigateClient.ts | 19 +++ test/background/mock/MockRepeatRepository.ts | 14 ++ test/background/mock/MockTabPresenter.ts | 179 +++++++++++++++++++++ test/background/mock/MockWindowPresenter.ts | 7 + test/background/mock/MockZoomPresenter.ts | 15 ++ .../operators/impls/CancelOperator.test.ts | 24 +++ .../operators/impls/CloseTabOperator.test.ts | 61 +++++++ .../operators/impls/CloseTabRightOperator.test.ts | 24 +++ .../impls/CommandOperatorFactoryChain.test.ts | 42 +++++ .../operators/impls/DuplicateTabOperator.test.ts | 25 +++ .../impls/InternalOpenURLOperator.test.ts | 0 .../impls/InternalOperatorFactoryChain.test.ts | 37 +++++ .../impls/NavigateHistoryNextOperator.test.ts | 25 +++ .../impls/NavigateHistoryPrevOperator.test.ts | 25 +++ .../impls/NavigateLinkNextOperator.test.ts | 22 +++ .../impls/NavigateLinkPrevOperator.test.ts | 22 +++ .../impls/NavigateOperatorFactoryChain.test.ts | 56 +++++++ .../operators/impls/NavigateParentOperator.test.ts | 53 ++++++ .../operators/impls/NavigateRootOperator.test.ts | 18 +++ .../operators/impls/OpenHomeOperator.test.ts | 70 ++++++++ .../operators/impls/OpenSourceOperator.test.ts | 21 +++ .../operators/impls/PinTabOperator.test.ts | 25 +++ .../operators/impls/ReloadTabOperator.test.ts | 34 ++++ .../operators/impls/ReopenTabOperator.test.ts | 17 ++ .../operators/impls/RepeatLastOperator.test.ts | 56 +++++++ .../impls/RepeatOperatorFactoryChain.test.ts | 32 ++++ .../operators/impls/ResetZoomOperator.test.ts | 17 ++ .../operators/impls/SelectFirstTabOperator.test.ts | 20 +++ .../operators/impls/SelectLastTabOperator.test.ts | 20 +++ .../SelectPreviousSelectedTabOperator.test.ts | 38 +++++ .../operators/impls/SelectTabNextOperator.test.ts | 35 ++++ .../operators/impls/SelectTabPrevOperator.test.ts | 35 ++++ .../impls/ShowAddBookmarkOperator.test.ts | 50 ++++++ .../impls/ShowBufferCommandOperator.test.ts | 25 +++ .../operators/impls/ShowCommandOperator.test.ts | 25 +++ .../impls/ShowOpenCommandOperator.test.ts | 50 ++++++ .../impls/ShowTabOpenCommandOperator.test.ts | 50 ++++++ .../impls/ShowWinOpenCommandOperator.test.ts | 50 ++++++ .../operators/impls/StartFindOperator.test.ts | 22 +++ .../impls/TabOperatorFactoryChain.test.ts | 71 ++++++++ .../impls/TogglePinnedTabOperator.test.ts | 32 ++++ .../operators/impls/UnpinTabOperator.test.ts | 25 +++ .../operators/impls/ZoomInOperator.test.ts | 17 ++ .../impls/ZoomOperatorFactoryChain.test.ts | 28 ++++ .../operators/impls/ZoomOutOperator.test.ts | 17 ++ 47 files changed, 1583 insertions(+) create mode 100644 test/background/mock/MockBrowserSettingRepository.ts create mode 100644 test/background/mock/MockConsoleClient.ts create mode 100644 test/background/mock/MockNavigateClient.ts create mode 100644 test/background/mock/MockRepeatRepository.ts create mode 100644 test/background/mock/MockTabPresenter.ts create mode 100644 test/background/mock/MockWindowPresenter.ts create mode 100644 test/background/mock/MockZoomPresenter.ts create mode 100644 test/background/operators/impls/CancelOperator.test.ts create mode 100644 test/background/operators/impls/CloseTabOperator.test.ts create mode 100644 test/background/operators/impls/CloseTabRightOperator.test.ts create mode 100644 test/background/operators/impls/CommandOperatorFactoryChain.test.ts create mode 100644 test/background/operators/impls/DuplicateTabOperator.test.ts create mode 100644 test/background/operators/impls/InternalOpenURLOperator.test.ts create mode 100644 test/background/operators/impls/InternalOperatorFactoryChain.test.ts create mode 100644 test/background/operators/impls/NavigateHistoryNextOperator.test.ts create mode 100644 test/background/operators/impls/NavigateHistoryPrevOperator.test.ts create mode 100644 test/background/operators/impls/NavigateLinkNextOperator.test.ts create mode 100644 test/background/operators/impls/NavigateLinkPrevOperator.test.ts create mode 100644 test/background/operators/impls/NavigateOperatorFactoryChain.test.ts create mode 100644 test/background/operators/impls/NavigateParentOperator.test.ts create mode 100644 test/background/operators/impls/NavigateRootOperator.test.ts create mode 100644 test/background/operators/impls/OpenHomeOperator.test.ts create mode 100644 test/background/operators/impls/OpenSourceOperator.test.ts create mode 100644 test/background/operators/impls/PinTabOperator.test.ts create mode 100644 test/background/operators/impls/ReloadTabOperator.test.ts create mode 100644 test/background/operators/impls/ReopenTabOperator.test.ts create mode 100644 test/background/operators/impls/RepeatLastOperator.test.ts create mode 100644 test/background/operators/impls/RepeatOperatorFactoryChain.test.ts create mode 100644 test/background/operators/impls/ResetZoomOperator.test.ts create mode 100644 test/background/operators/impls/SelectFirstTabOperator.test.ts create mode 100644 test/background/operators/impls/SelectLastTabOperator.test.ts create mode 100644 test/background/operators/impls/SelectPreviousSelectedTabOperator.test.ts create mode 100644 test/background/operators/impls/SelectTabNextOperator.test.ts create mode 100644 test/background/operators/impls/SelectTabPrevOperator.test.ts create mode 100644 test/background/operators/impls/ShowAddBookmarkOperator.test.ts create mode 100644 test/background/operators/impls/ShowBufferCommandOperator.test.ts create mode 100644 test/background/operators/impls/ShowCommandOperator.test.ts create mode 100644 test/background/operators/impls/ShowOpenCommandOperator.test.ts create mode 100644 test/background/operators/impls/ShowTabOpenCommandOperator.test.ts create mode 100644 test/background/operators/impls/ShowWinOpenCommandOperator.test.ts create mode 100644 test/background/operators/impls/StartFindOperator.test.ts create mode 100644 test/background/operators/impls/TabOperatorFactoryChain.test.ts create mode 100644 test/background/operators/impls/TogglePinnedTabOperator.test.ts create mode 100644 test/background/operators/impls/UnpinTabOperator.test.ts create mode 100644 test/background/operators/impls/ZoomInOperator.test.ts create mode 100644 test/background/operators/impls/ZoomOperatorFactoryChain.test.ts create mode 100644 test/background/operators/impls/ZoomOutOperator.test.ts (limited to 'test') diff --git a/test/background/mock/MockBrowserSettingRepository.ts b/test/background/mock/MockBrowserSettingRepository.ts new file mode 100644 index 0000000..22e7084 --- /dev/null +++ b/test/background/mock/MockBrowserSettingRepository.ts @@ -0,0 +1,10 @@ +import BrowserSettingRepository from "../../../src/background/repositories/BrowserSettingRepository"; + +export default class MockBrowserSettingRepository + implements BrowserSettingRepository { + constructor(private readonly homepageUrls: string[]) {} + + getHomepageUrls(): Promise { + return Promise.resolve(this.homepageUrls); + } +} diff --git a/test/background/mock/MockConsoleClient.ts b/test/background/mock/MockConsoleClient.ts new file mode 100644 index 0000000..d1f8fc3 --- /dev/null +++ b/test/background/mock/MockConsoleClient.ts @@ -0,0 +1,23 @@ +import ConsoleClient from "../../../src/background/infrastructures/ConsoleClient"; + +export default class MockConsoleClient implements ConsoleClient { + hide(_tabId: number): Promise { + throw new Error("not implemented"); + } + + showCommand(_tabId: number, _command: string): Promise { + throw new Error("not implemented"); + } + + showError(_tabId: number, _message: string): Promise { + throw new Error("not implemented"); + } + + showFind(_tabId: number): Promise { + throw new Error("not implemented"); + } + + showInfo(_tabId: number, _message: string): Promise { + throw new Error("not implemented"); + } +} diff --git a/test/background/mock/MockNavigateClient.ts b/test/background/mock/MockNavigateClient.ts new file mode 100644 index 0000000..d9442a4 --- /dev/null +++ b/test/background/mock/MockNavigateClient.ts @@ -0,0 +1,19 @@ +import NavigateClient from "../../../src/background/clients/NavigateClient"; + +export default class MockNavigateClient implements NavigateClient { + historyNext(_tabId: number): Promise { + throw new Error("not implemented"); + } + + historyPrev(_tabId: number): Promise { + throw new Error("not implemented"); + } + + linkNext(_tabId: number): Promise { + throw new Error("not implemented"); + } + + linkPrev(_tabId: number): Promise { + throw new Error("not implemented"); + } +} diff --git a/test/background/mock/MockRepeatRepository.ts b/test/background/mock/MockRepeatRepository.ts new file mode 100644 index 0000000..1a686c8 --- /dev/null +++ b/test/background/mock/MockRepeatRepository.ts @@ -0,0 +1,14 @@ +import RepeatRepository from "../../../src/background/repositories/RepeatRepository"; +import { Operation } from "../../../src/shared/operations"; + +export default class MockRepeatRepository implements RepeatRepository { + private op: Operation | undefined = undefined; + + getLastOperation(): Operation | undefined { + return this.op; + } + + setLastOperation(op: Operation): void { + this.op = op; + } +} diff --git a/test/background/mock/MockTabPresenter.ts b/test/background/mock/MockTabPresenter.ts new file mode 100644 index 0000000..22fb947 --- /dev/null +++ b/test/background/mock/MockTabPresenter.ts @@ -0,0 +1,179 @@ +import TabPresenter from "../../../src/background/presenters/TabPresenter"; + +export default class MockTabPresenter implements TabPresenter { + private readonly tabs: browser.tabs.Tab[] = []; + private readonly zooms: number[] = []; + private nextid = 0; + + private readonly lastSelectedId: number | undefined; + + private static defaultTabOptions = { + hidden: false, + highlighted: false, + incognito: false, + isArticle: false, + isInReaderMode: false, + lastAccessed: 0, + pinned: false, + selected: false, + windowId: 0, + }; + + create( + url: string, + opts?: { + active?: boolean; + cookieStoreId?: string; + index?: number; + openerTabId?: number; + pinned?: boolean; + windowId?: number; + } + ): Promise { + const tab = { + ...MockTabPresenter.defaultTabOptions, + ...opts, + id: this.nextid++, + active: false, + title: "welcome, world", + url, + index: this.tabs.length, + }; + if (opts?.active || this.tabs.length === 0) { + this.tabs.forEach((t) => (t.active = false)); + tab.active = true; + } + this.tabs.push(tab); + this.zooms.push(1); + return Promise.resolve(tab); + } + + duplicate(id: number): Promise { + const src = this.tabs.find((t) => t.id === id); + if (!src) { + throw new Error(`tab ${id} not found`); + } + this.tabs.forEach((t) => (t.active = false)); + const tab = { ...src, id: this.nextid++, active: true }; + this.tabs.push(tab); + this.zooms.push(1); + + return Promise.resolve(tab); + } + + getAll(): Promise { + return Promise.resolve([...this.tabs]); + } + + getByKeyword( + keyword: string, + excludePinned: boolean + ): Promise { + const tabs = this.tabs + + .filter((t) => { + return ( + (t.url && t.url.toLowerCase().includes(keyword.toLowerCase())) || + (t.title && t.title.toLowerCase().includes(keyword.toLowerCase())) + ); + }) + .filter((t) => { + return !(excludePinned && t.pinned); + }); + return Promise.resolve(tabs); + } + + getCurrent(): Promise { + const tab = this.tabs.find((t) => t.active); + if (!tab) { + throw new Error("active tab not found"); + } + return Promise.resolve(tab); + } + + getLastSelectedId(): Promise { + return Promise.resolve(this.lastSelectedId); + } + + getZoom(tabId: number): Promise { + const index = this.tabs.findIndex((t) => t.id === tabId); + if (index === -1) { + throw new Error(`tab ${tabId} not found`); + } + return Promise.resolve(this.zooms[index]); + } + + onSelected( + _listener: (arg: { tabId: number; windowId: number }) => void + ): void { + throw new Error("not implemented"); + } + + open(url: string, tabId?: number): Promise { + let tab = this.tabs.find((t) => t.active); + if (!tab) { + throw new Error(`active tab not found`); + } + if (tabId !== undefined) { + tab = this.tabs.find((t) => t.id === tabId); + } + if (!tab) { + throw new Error(`tab ${tabId} not found`); + } + tab.url = url; + return Promise.resolve(tab); + } + + reload(_tabId: number, _cache: boolean): Promise { + throw new Error("not implemented"); + } + + remove(ids: number[]): Promise { + for (const id of ids) { + const index = this.tabs.findIndex((t) => t.id === id); + if (index === -1) { + throw new Error(`tab ${id} not found`); + } + const tab = this.tabs[index]; + this.tabs.splice(index, 1); + this.zooms.splice(index, 1); + if (tab.active) { + this.tabs[Math.min(index, this.tabs.length - 1)].active = true; + } + } + + return Promise.resolve(undefined); + } + + reopen(): Promise { + throw new Error("not implemented"); + } + + select(tabId: number): Promise { + const tab = this.tabs.find((t) => t.id === tabId); + if (!tab) { + throw new Error(`tab ${tabId} not found`); + } + this.tabs.forEach((t) => (t.active = false)); + tab.active = true; + return Promise.resolve(undefined); + } + + setPinned(tabId: number, pinned: boolean): Promise { + const tab = this.tabs.find((t) => t.id === tabId); + if (!tab) { + throw new Error(`tab ${tabId} not found`); + } + tab.pinned = pinned; + return Promise.resolve(); + } + + setZoom(tabId: number, factor: number): Promise { + const index = this.tabs.findIndex((t) => t.id === tabId); + if (index === -1) { + throw new Error(`tab ${tabId} not found`); + } + this.zooms[index] = factor; + return Promise.resolve(); + } +} diff --git a/test/background/mock/MockWindowPresenter.ts b/test/background/mock/MockWindowPresenter.ts new file mode 100644 index 0000000..420ae8b --- /dev/null +++ b/test/background/mock/MockWindowPresenter.ts @@ -0,0 +1,7 @@ +import WindowPresenter from "../../../src/background/presenters/WindowPresenter"; + +export default class MockWindowPresenter implements WindowPresenter { + create(_url: string): Promise { + throw new Error("not implemented"); + } +} diff --git a/test/background/mock/MockZoomPresenter.ts b/test/background/mock/MockZoomPresenter.ts new file mode 100644 index 0000000..a1ca100 --- /dev/null +++ b/test/background/mock/MockZoomPresenter.ts @@ -0,0 +1,15 @@ +import ZoomPresenter from "../../../src/background/usecases/ZoomPresenter"; + +export default class MockZoomPresenter implements ZoomPresenter { + resetZoom(): Promise { + throw new Error("not implemented"); + } + + zoomIn(): Promise { + throw new Error("not implemented"); + } + + zoomOut(): Promise { + throw new Error("not implemented"); + } +} diff --git a/test/background/operators/impls/CancelOperator.test.ts b/test/background/operators/impls/CancelOperator.test.ts new file mode 100644 index 0000000..915becf --- /dev/null +++ b/test/background/operators/impls/CancelOperator.test.ts @@ -0,0 +1,24 @@ +import sinon from "sinon"; +import CancelOperator from "../../../../src/background/operators/impls/CancelOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("CancelOperator", () => { + describe("#run", () => { + it("hides console", async () => { + const tabPresenter = new MockTabPresenter(); + const currenTab = await tabPresenter.create("https://example.com/"); + + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("hide") + .withArgs(currenTab?.id); + const sut = new CancelOperator(tabPresenter, consoleClient); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/CloseTabOperator.test.ts b/test/background/operators/impls/CloseTabOperator.test.ts new file mode 100644 index 0000000..ba9cbfe --- /dev/null +++ b/test/background/operators/impls/CloseTabOperator.test.ts @@ -0,0 +1,61 @@ +import { expect } from "chai"; +import CloseTabOperator from "../../../../src/background/operators/impls/CloseTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("CloseTabOperator", () => { + describe("#run", () => { + it("close a current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new CloseTabOperator(tabPresenter); + + await sut.run(); + + const tabs = await tabPresenter.getAll(); + expect(tabs.map((t) => t.url)).to.deep.equal([ + "https://example.com/1", + "https://example.com/3", + ]); + }); + + it("close a current tab forcely", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { + pinned: true, + active: false, + }); + await tabPresenter.create("https://example.com/2", { + pinned: true, + active: true, + }); + await tabPresenter.create("https://example.com/3", { + pinned: true, + active: false, + }); + const sut = new CloseTabOperator(tabPresenter, true); + + await sut.run(); + + const tabs = await tabPresenter.getAll(); + expect(tabs.map((t) => t.url)).to.deep.equal([ + "https://example.com/1", + "https://example.com/3", + ]); + }); + + it("close a current tab and select left of the closed tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new CloseTabOperator(tabPresenter, false, true); + + await sut.run(); + + const tab = await tabPresenter.getCurrent(); + expect(tab.url).to.equal("https://example.com/1"); + }); + }); +}); diff --git a/test/background/operators/impls/CloseTabRightOperator.test.ts b/test/background/operators/impls/CloseTabRightOperator.test.ts new file mode 100644 index 0000000..c2a106c --- /dev/null +++ b/test/background/operators/impls/CloseTabRightOperator.test.ts @@ -0,0 +1,24 @@ +import { expect } from "chai"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import CloseTabRightOperator from "../../../../src/background/operators/impls/CloseTabRightOperator"; + +describe("CloseTabRightOperator", () => { + describe("#run", () => { + it("close the right of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + await tabPresenter.create("https://example.com/4", { active: false }); + const sut = new CloseTabRightOperator(tabPresenter); + + await sut.run(); + + const tabs = await tabPresenter.getAll(); + expect(tabs.map((t) => t.url)).to.deep.equal([ + "https://example.com/1", + "https://example.com/2", + ]); + }); + }); +}); diff --git a/test/background/operators/impls/CommandOperatorFactoryChain.test.ts b/test/background/operators/impls/CommandOperatorFactoryChain.test.ts new file mode 100644 index 0000000..e481c5a --- /dev/null +++ b/test/background/operators/impls/CommandOperatorFactoryChain.test.ts @@ -0,0 +1,42 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import CommandOperatorFactoryChain from "../../../../src/background/operators/impls/CommandOperatorFactoryChain"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; +import * as operations from "../../../../src/shared/operations"; +import ShowCommandOperator from "../../../../src/background/operators/impls/ShowCommandOperator"; +import ShowTabOpenCommandOperator from "../../../../src/background/operators/impls/ShowTabOpenCommandOperator"; +import ShowWinOpenCommandOperator from "../../../../src/background/operators/impls/ShowWinOpenCommandOperator"; +import ShowBufferCommandOperator from "../../../../src/background/operators/impls/ShowBufferCommandOperator"; +import ShowAddBookmarkOperator from "../../../../src/background/operators/impls/ShowAddBookmarkOperator"; +import StartFindOperator from "../../../../src/background/operators/impls/StartFindOperator"; + +describe("CommandOperatorFactoryChain", () => { + describe("#create", () => { + it("returns a operator for the operation", async () => { + const tabPresenter = new MockTabPresenter(); + const consoleClient = new MockConsoleClient(); + const sut = new CommandOperatorFactoryChain(tabPresenter, consoleClient); + + expect(sut.create({ type: operations.COMMAND_SHOW })).to.be.instanceOf( + ShowCommandOperator + ); + expect( + sut.create({ type: operations.COMMAND_SHOW_TABOPEN, alter: true }) + ).to.be.instanceOf(ShowTabOpenCommandOperator); + expect( + sut.create({ type: operations.COMMAND_SHOW_WINOPEN, alter: true }) + ).to.be.instanceOf(ShowWinOpenCommandOperator); + expect( + sut.create({ type: operations.COMMAND_SHOW_BUFFER }) + ).to.be.instanceOf(ShowBufferCommandOperator); + expect( + sut.create({ type: operations.COMMAND_SHOW_ADDBOOKMARK, alter: true }) + ).to.be.instanceOf(ShowAddBookmarkOperator); + expect(sut.create({ type: operations.FIND_START })).to.be.instanceOf( + StartFindOperator + ); + expect(sut.create({ type: operations.CANCEL })).to.be.null; + }); + }); +}); diff --git a/test/background/operators/impls/DuplicateTabOperator.test.ts b/test/background/operators/impls/DuplicateTabOperator.test.ts new file mode 100644 index 0000000..ce2c19d --- /dev/null +++ b/test/background/operators/impls/DuplicateTabOperator.test.ts @@ -0,0 +1,25 @@ +import { expect } from "chai"; +import DuplicateTabOperator from "../../../../src/background/operators/impls/DuplicateTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("DuplicateTabOperator", () => { + describe("#run", () => { + it("duplicate a tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new DuplicateTabOperator(tabPresenter); + + await sut.run(); + + const tabs = await tabPresenter.getAll(); + expect(tabs.map((t) => t.url)).to.deep.equal([ + "https://example.com/1", + "https://example.com/2", + "https://example.com/3", + "https://example.com/2", + ]); + }); + }); +}); diff --git a/test/background/operators/impls/InternalOpenURLOperator.test.ts b/test/background/operators/impls/InternalOpenURLOperator.test.ts new file mode 100644 index 0000000..e69de29 diff --git a/test/background/operators/impls/InternalOperatorFactoryChain.test.ts b/test/background/operators/impls/InternalOperatorFactoryChain.test.ts new file mode 100644 index 0000000..09029db --- /dev/null +++ b/test/background/operators/impls/InternalOperatorFactoryChain.test.ts @@ -0,0 +1,37 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import InternalOperatorFactoryChain from "../../../../src/background/operators/impls/InternalOperatorFactoryChain"; +import MockWindowPresenter from "../../mock/MockWindowPresenter"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; +import CancelOperator from "../../../../src/background/operators/impls/CancelOperator"; +import InternalOpenURLOperator from "../../../../src/background/operators/impls/InternalOpenURLOperator"; +import * as operations from "../../../../src/shared/operations"; + +describe("InternalOperatorFactoryChain", () => { + describe("#create", () => { + it("returns a operator for the operation", async () => { + const windowPresenter = new MockWindowPresenter(); + const tabPresenter = new MockTabPresenter(); + const consoleClient = new MockConsoleClient(); + const sut = new InternalOperatorFactoryChain( + windowPresenter, + tabPresenter, + consoleClient + ); + + expect(sut.create({ type: operations.CANCEL })).to.be.instanceOf( + CancelOperator + ); + expect( + sut.create({ + type: operations.INTERNAL_OPEN_URL, + url: "https://example.com", + newTab: false, + newWindow: false, + }) + ).to.be.instanceOf(InternalOpenURLOperator); + expect(sut.create({ type: operations.COMMAND_SHOW })).to.be.null; + }); + }); +}); diff --git a/test/background/operators/impls/NavigateHistoryNextOperator.test.ts b/test/background/operators/impls/NavigateHistoryNextOperator.test.ts new file mode 100644 index 0000000..de8f597 --- /dev/null +++ b/test/background/operators/impls/NavigateHistoryNextOperator.test.ts @@ -0,0 +1,25 @@ +import sinon from "sinon"; +import NavigateHistoryNextOperator from "../../../../src/background/operators/impls/NavigateHistoryNextOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockNavigateClient from "../../mock/MockNavigateClient"; + +describe("NavigateHistoryNextOperator", () => { + describe("#run", () => { + it("send a message to navigate next in the history", async () => { + const navigateClient = new MockNavigateClient(); + const mock = sinon + .mock(navigateClient) + .expects("historyNext") + .withArgs(1); + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new NavigateHistoryNextOperator(tabPresenter, navigateClient); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/NavigateHistoryPrevOperator.test.ts b/test/background/operators/impls/NavigateHistoryPrevOperator.test.ts new file mode 100644 index 0000000..6ebe71e --- /dev/null +++ b/test/background/operators/impls/NavigateHistoryPrevOperator.test.ts @@ -0,0 +1,25 @@ +import sinon from "sinon"; +import NavigateHistoryPrevOperator from "../../../../src/background/operators/impls/NavigateHistoryPrevOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockNavigateClient from "../../mock/MockNavigateClient"; + +describe("NavigateHistoryPrevOperator", () => { + describe("#run", () => { + it("send a message to navigate previous in the history", async () => { + const navigateClient = new MockNavigateClient(); + const mock = sinon + .mock(navigateClient) + .expects("historyPrev") + .withArgs(1); + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new NavigateHistoryPrevOperator(tabPresenter, navigateClient); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/NavigateLinkNextOperator.test.ts b/test/background/operators/impls/NavigateLinkNextOperator.test.ts new file mode 100644 index 0000000..09c4907 --- /dev/null +++ b/test/background/operators/impls/NavigateLinkNextOperator.test.ts @@ -0,0 +1,22 @@ +import sinon from "sinon"; +import NavigateLinkNextOperator from "../../../../src/background/operators/impls/NavigateLinkNextOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockNavigateClient from "../../mock/MockNavigateClient"; + +describe("NavigateLinkNextOperator", () => { + describe("#run", () => { + it("send a message to navigate next page", async () => { + const navigateClient = new MockNavigateClient(); + const mock = sinon.mock(navigateClient).expects("linkNext").withArgs(1); + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new NavigateLinkNextOperator(tabPresenter, navigateClient); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/NavigateLinkPrevOperator.test.ts b/test/background/operators/impls/NavigateLinkPrevOperator.test.ts new file mode 100644 index 0000000..6b7f791 --- /dev/null +++ b/test/background/operators/impls/NavigateLinkPrevOperator.test.ts @@ -0,0 +1,22 @@ +import sinon from "sinon"; +import NavigateLinkPrevOperator from "../../../../src/background/operators/impls/NavigateLinkPrevOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockNavigateClient from "../../mock/MockNavigateClient"; + +describe("NavigateLinkPrevOperator", () => { + describe("#run", () => { + it("send a message to navigate next page", async () => { + const navigateClient = new MockNavigateClient(); + const mock = sinon.mock(navigateClient).expects("linkPrev").withArgs(1); + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const sut = new NavigateLinkPrevOperator(tabPresenter, navigateClient); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/NavigateOperatorFactoryChain.test.ts b/test/background/operators/impls/NavigateOperatorFactoryChain.test.ts new file mode 100644 index 0000000..dfb5654 --- /dev/null +++ b/test/background/operators/impls/NavigateOperatorFactoryChain.test.ts @@ -0,0 +1,56 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import NavigateOperatorFactoryChain from "../../../../src/background/operators/impls/NavigateOperatorFactoryChain"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockNavigateClient from "../../mock/MockNavigateClient"; +import MockBrowserSettingRepository from "../../mock/MockBrowserSettingRepository"; +import NavigateHistoryPrevOperator from "../../../../src/background/operators/impls/NavigateHistoryPrevOperator"; +import NavigateHistoryNextOperator from "../../../../src/background/operators/impls/NavigateHistoryNextOperator"; +import NavigateLinkPrevOperator from "../../../../src/background/operators/impls/NavigateLinkPrevOperator"; +import NavigateLinkNextOperator from "../../../../src/background/operators/impls/NavigateLinkNextOperator"; +import NavigateParentOperator from "../../../../src/background/operators/impls/NavigateParentOperator"; +import NavigateRootOperator from "../../../../src/background/operators/impls/NavigateRootOperator"; +import OpenHomeOperator from "../../../../src/background/operators/impls/OpenHomeOperator"; +import OpenSourceOperator from "../../../../src/background/operators/impls/OpenSourceOperator"; +import * as operations from "../../../../src/shared/operations"; + +describe("NavigateOperatorFactoryChain", () => { + describe("#create", () => { + it("returns a operator for the operation", async () => { + const tabPresenter = new MockTabPresenter(); + const navigateClient = new MockNavigateClient(); + const browserSettingRepository = new MockBrowserSettingRepository([]); + const sut = new NavigateOperatorFactoryChain( + tabPresenter, + navigateClient, + browserSettingRepository + ); + + expect( + sut.create({ type: operations.NAVIGATE_HISTORY_PREV }) + ).to.be.instanceOf(NavigateHistoryPrevOperator); + expect( + sut.create({ type: operations.NAVIGATE_HISTORY_NEXT }) + ).to.be.instanceOf(NavigateHistoryNextOperator); + expect( + sut.create({ type: operations.NAVIGATE_LINK_PREV }) + ).to.be.instanceOf(NavigateLinkPrevOperator); + expect( + sut.create({ type: operations.NAVIGATE_LINK_NEXT }) + ).to.be.instanceOf(NavigateLinkNextOperator); + expect(sut.create({ type: operations.NAVIGATE_PARENT })).to.be.instanceOf( + NavigateParentOperator + ); + expect(sut.create({ type: operations.NAVIGATE_ROOT })).to.be.instanceOf( + NavigateRootOperator + ); + expect(sut.create({ type: operations.PAGE_SOURCE })).to.be.instanceOf( + OpenSourceOperator + ); + expect( + sut.create({ type: operations.PAGE_HOME, newTab: false }) + ).to.be.instanceOf(OpenHomeOperator); + expect(sut.create({ type: operations.CANCEL })).to.be.null; + }); + }); +}); diff --git a/test/background/operators/impls/NavigateParentOperator.test.ts b/test/background/operators/impls/NavigateParentOperator.test.ts new file mode 100644 index 0000000..cc57f17 --- /dev/null +++ b/test/background/operators/impls/NavigateParentOperator.test.ts @@ -0,0 +1,53 @@ +import { expect } from "chai"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import NavigateParentOperator from "../../../../src/background/operators/impls/NavigateParentOperator"; + +describe("NavigateParentOperator", () => { + describe("#run", () => { + it("opens a parent directory of the file in the URL", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/fruits/yellow/banana", { + active: true, + }); + const sut = new NavigateParentOperator(tabPresenter); + + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.be.equal("https://example.com/fruits/yellow/"); + }); + + it("opens a parent directory of the directoryin the URL", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/fruits/yellow/"); + const sut = new NavigateParentOperator(tabPresenter); + + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.be.equal("https://example.com/fruits/"); + }); + + it("removes a hash in the URL", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/fruits/yellow/#top"); + const sut = new NavigateParentOperator(tabPresenter); + + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.be.equal("https://example.com/fruits/yellow/"); + }); + + it("removes query parameters in the URL", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/search?q=apple"); + const sut = new NavigateParentOperator(tabPresenter); + + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.be.equal("https://example.com/search"); + }); + }); +}); diff --git a/test/background/operators/impls/NavigateRootOperator.test.ts b/test/background/operators/impls/NavigateRootOperator.test.ts new file mode 100644 index 0000000..bbe574c --- /dev/null +++ b/test/background/operators/impls/NavigateRootOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import NavigateRootOperator from "../../../../src/background/operators/impls/NavigateRootOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("NavigateRootOperator", () => { + describe("#run", () => { + it("opens root directory in the URL", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/search?q=apple#top"); + const sut = new NavigateRootOperator(tabPresenter); + + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.be.equal("https://example.com"); + }); + }); +}); diff --git a/test/background/operators/impls/OpenHomeOperator.test.ts b/test/background/operators/impls/OpenHomeOperator.test.ts new file mode 100644 index 0000000..3c9288f --- /dev/null +++ b/test/background/operators/impls/OpenHomeOperator.test.ts @@ -0,0 +1,70 @@ +import { expect } from "chai"; +import OpenHomeOperator from "../../../../src/background/operators/impls/OpenHomeOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockBrowserSettingRepository from "../../mock/MockBrowserSettingRepository"; + +describe("OpenHomeOperator", () => { + describe("#run", () => { + it("opens a home page of the browser into the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/"); + const browserSettingRepository = new MockBrowserSettingRepository([ + "https://example.net/", + ]); + const sut = new OpenHomeOperator( + tabPresenter, + browserSettingRepository, + false + ); + + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.be.equal("https://example.net/"); + }); + + it("opens a home page of the browser into a new tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/"); + const browserSettingRepository = new MockBrowserSettingRepository([ + "https://example.net/", + ]); + const sut = new OpenHomeOperator( + tabPresenter, + browserSettingRepository, + true + ); + + await sut.run(); + + const urls = (await tabPresenter.getAll()).map((t) => t.url); + expect(urls).to.be.deep.equal([ + "https://example.com/", + "https://example.net/", + ]); + }); + + it("opens home pages of the browser", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/"); + const browserSettingRepository = new MockBrowserSettingRepository([ + "https://example.net/", + "https://example.org/", + ]); + const sut = new OpenHomeOperator( + tabPresenter, + browserSettingRepository, + false + ); + + await sut.run(); + + const urls = (await tabPresenter.getAll()).map((t) => t.url); + expect(urls).to.be.deep.equal([ + "https://example.com/", + "https://example.net/", + "https://example.org/", + ]); + }); + }); +}); diff --git a/test/background/operators/impls/OpenSourceOperator.test.ts b/test/background/operators/impls/OpenSourceOperator.test.ts new file mode 100644 index 0000000..541032b --- /dev/null +++ b/test/background/operators/impls/OpenSourceOperator.test.ts @@ -0,0 +1,21 @@ +import { expect } from "chai"; +import OpenSourceOperator from "../../../../src/background/operators/impls/OpenSourceOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("OpenSourceOperator", () => { + describe("#run", () => { + it("opens view-source URL of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/"); + const sut = new OpenSourceOperator(tabPresenter); + + await sut.run(); + + const urls = (await tabPresenter.getAll()).map((t) => t.url); + expect(urls).to.be.deep.equal([ + "https://example.com/", + "view-source:https://example.com/", + ]); + }); + }); +}); diff --git a/test/background/operators/impls/PinTabOperator.test.ts b/test/background/operators/impls/PinTabOperator.test.ts new file mode 100644 index 0000000..0c940b6 --- /dev/null +++ b/test/background/operators/impls/PinTabOperator.test.ts @@ -0,0 +1,25 @@ +import { expect } from "chai"; +import PinTabOperator from "../../../../src/background/operators/impls/PinTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("PinTabOperator", () => { + describe("#run", () => { + it("make pinned to the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/", { + active: true, + pinned: false, + }); + await tabPresenter.create("https://example.com/", { + active: false, + pinned: false, + }); + const sut = new PinTabOperator(tabPresenter); + + await sut.run(); + + const pins = (await tabPresenter.getAll()).map((t) => t.pinned); + expect(pins).to.deep.equal([true, false]); + }); + }); +}); diff --git a/test/background/operators/impls/ReloadTabOperator.test.ts b/test/background/operators/impls/ReloadTabOperator.test.ts new file mode 100644 index 0000000..e87782b --- /dev/null +++ b/test/background/operators/impls/ReloadTabOperator.test.ts @@ -0,0 +1,34 @@ +import sinon from "sinon"; +import ReloadTabOperator from "../../../../src/background/operators/impls/ReloadTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("ReloadTabOperator", () => { + describe("#run", () => { + it("reloads the current tab with cache", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/", { active: true }); + await tabPresenter.create("https://example.com/", { active: false }); + const mock = sinon.mock(tabPresenter).expects("reload").withArgs(0, true); + + const sut = new ReloadTabOperator(tabPresenter, true); + await sut.run(); + + mock.verify(); + }); + + it("reloads the current tab without cache", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/", { active: true }); + await tabPresenter.create("https://example.com/", { active: false }); + const mock = sinon + .mock(tabPresenter) + .expects("reload") + .withArgs(0, false); + + const sut = new ReloadTabOperator(tabPresenter, false); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ReopenTabOperator.test.ts b/test/background/operators/impls/ReopenTabOperator.test.ts new file mode 100644 index 0000000..43b1575 --- /dev/null +++ b/test/background/operators/impls/ReopenTabOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import ReopenTabOperator from "../../../../src/background/operators/impls/ReopenTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("ReopenTabOperator", () => { + describe("#run", () => { + it("reopens closed tabs", async () => { + const tabPresenter = new MockTabPresenter(); + const mock = sinon.mock(tabPresenter).expects("reopen"); + + const sut = new ReopenTabOperator(tabPresenter); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/RepeatLastOperator.test.ts b/test/background/operators/impls/RepeatLastOperator.test.ts new file mode 100644 index 0000000..57f1227 --- /dev/null +++ b/test/background/operators/impls/RepeatLastOperator.test.ts @@ -0,0 +1,56 @@ +import RepeatLastOperator from "../../../../src/background/operators/impls/RepeatLastOperator"; +import MockRepeatRepository from "../../mock/MockRepeatRepository"; +import OperatorFactory from "../../../../src/background/operators/OperatorFactory"; +import * as operations from "../../../../src/shared/operations"; +import Operator from "../../../../src/background/operators/Operator"; +import sinon from "sinon"; + +class MockOperatorFactory implements OperatorFactory { + create(_op: operations.Operation): Operator { + throw new Error("not implemented"); + } +} + +class MockOperator implements Operator { + run(): Promise { + throw new Error("not implemented"); + } +} + +describe("RepeatLastOperator", () => { + describe("#run", () => { + it("repeat last operation", async () => { + const operator = new MockOperator(); + const operatorMock = sinon.mock(operator).expects("run").once(); + const repeatRepository = new MockRepeatRepository(); + repeatRepository.setLastOperation({ type: operations.CANCEL }); + + const operatorFactory = new MockOperatorFactory(); + const operatorFactoryMock = sinon + .mock(operatorFactory) + .expects("create") + .withArgs({ type: operations.CANCEL }); + operatorFactoryMock.returns(operator); + + const sut = new RepeatLastOperator(repeatRepository, operatorFactory); + await sut.run(); + + operatorFactoryMock.verify(); + operatorMock.verify(); + }); + + it("does nothing if no last operations", async () => { + const repeatRepository = new MockRepeatRepository(); + const operatorFactory = new MockOperatorFactory(); + const operatorFactoryMock = sinon + .mock(operatorFactory) + .expects("create") + .never(); + + const sut = new RepeatLastOperator(repeatRepository, operatorFactory); + await sut.run(); + + operatorFactoryMock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/RepeatOperatorFactoryChain.test.ts b/test/background/operators/impls/RepeatOperatorFactoryChain.test.ts new file mode 100644 index 0000000..e12d788 --- /dev/null +++ b/test/background/operators/impls/RepeatOperatorFactoryChain.test.ts @@ -0,0 +1,32 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import RepeatOperatorFactoryChain from "../../../../src/background/operators/impls/RepeatOperatorFactoryChain"; +import RepeatLastOperator from "../../../../src/background/operators/impls/RepeatLastOperator"; +import OperatorFactory from "../../../../src/background/operators/OperatorFactory"; +import MockRepeatRepository from "../../mock/MockRepeatRepository"; +import Operator from "../../../../src/content/operators/Operator"; +import * as operations from "../../../../src/shared/operations"; + +class MockOperatorFactory implements OperatorFactory { + create(_op: operations.Operation): Operator { + throw new Error("not implemented"); + } +} + +describe("RepeatOperatorFactoryChain", () => { + describe("#create", () => { + it("returns a operator for the operation", async () => { + const repeatRepository = new MockRepeatRepository(); + const operatorFactory = new MockOperatorFactory(); + const sut = new RepeatOperatorFactoryChain( + repeatRepository, + operatorFactory + ); + + expect(sut.create({ type: operations.REPEAT_LAST })).to.be.instanceOf( + RepeatLastOperator + ); + expect(sut.create({ type: operations.CANCEL })).to.be.null; + }); + }); +}); diff --git a/test/background/operators/impls/ResetZoomOperator.test.ts b/test/background/operators/impls/ResetZoomOperator.test.ts new file mode 100644 index 0000000..68cda05 --- /dev/null +++ b/test/background/operators/impls/ResetZoomOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import ResetZoomOperator from "../../../../src/background/operators/impls/ResetZoomOperator"; +import MockZoomPresenter from "../../mock/MockZoomPresenter"; + +describe("ResetZoomOperator", () => { + describe("#run", () => { + it("resets zoom on the tab", async () => { + const zoomPresenter = new MockZoomPresenter(); + const mock = sinon.mock(zoomPresenter).expects("resetZoom").once(); + + const sut = new ResetZoomOperator(zoomPresenter); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/SelectFirstTabOperator.test.ts b/test/background/operators/impls/SelectFirstTabOperator.test.ts new file mode 100644 index 0000000..a3f1d7e --- /dev/null +++ b/test/background/operators/impls/SelectFirstTabOperator.test.ts @@ -0,0 +1,20 @@ +import { expect } from "chai"; +import SelectFirstTabOperator from "../../../../src/background/operators/impls/SelectFirstTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("SelectFirstTabOperator", () => { + describe("#run", () => { + it("select the leftmost tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + + const sut = new SelectFirstTabOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/1"); + }); + }); +}); diff --git a/test/background/operators/impls/SelectLastTabOperator.test.ts b/test/background/operators/impls/SelectLastTabOperator.test.ts new file mode 100644 index 0000000..b8cf5c4 --- /dev/null +++ b/test/background/operators/impls/SelectLastTabOperator.test.ts @@ -0,0 +1,20 @@ +import { expect } from "chai"; +import SelectLastTabOperator from "../../../../src/background/operators/impls/SelectLastTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("SelectLastTabOperator", () => { + describe("#run", () => { + it("select the rightmost tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + + const sut = new SelectLastTabOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/3"); + }); + }); +}); diff --git a/test/background/operators/impls/SelectPreviousSelectedTabOperator.test.ts b/test/background/operators/impls/SelectPreviousSelectedTabOperator.test.ts new file mode 100644 index 0000000..5e6cc73 --- /dev/null +++ b/test/background/operators/impls/SelectPreviousSelectedTabOperator.test.ts @@ -0,0 +1,38 @@ +import { expect } from "chai"; +import sinon from "sinon"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import SelectPreviousSelectedTabOperator from "../../../../src/background/operators/impls/SelectPreviousSelectedTabOperator"; + +describe("SelectPreviousSelectedTabOperator", () => { + describe("#run", () => { + it("select the last-selected tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + sinon.stub(tabPresenter, "getLastSelectedId").returns(Promise.resolve(0)); + + const sut = new SelectPreviousSelectedTabOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/1"); + }); + + it("do nothing if no last-selected tabs", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + sinon + .stub(tabPresenter, "getLastSelectedId") + .returns(Promise.resolve(undefined)); + const mock = sinon.mock(tabPresenter).expects("select").never(); + + const sut = new SelectPreviousSelectedTabOperator(tabPresenter); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/SelectTabNextOperator.test.ts b/test/background/operators/impls/SelectTabNextOperator.test.ts new file mode 100644 index 0000000..5952d92 --- /dev/null +++ b/test/background/operators/impls/SelectTabNextOperator.test.ts @@ -0,0 +1,35 @@ +import { expect } from "chai"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import SelectTabNextOperator from "../../../../src/background/operators/impls/SelectTabNextOperator"; + +describe("SelectTabNextOperator", () => { + describe("#run", () => { + it("select a right tab of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + + const sut = new SelectTabNextOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/3"); + }); + }); + + describe("#run", () => { + it("select a right tab of the current tab in rotation", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: false }); + await tabPresenter.create("https://example.com/3", { active: true }); + + const sut = new SelectTabNextOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/1"); + }); + }); +}); diff --git a/test/background/operators/impls/SelectTabPrevOperator.test.ts b/test/background/operators/impls/SelectTabPrevOperator.test.ts new file mode 100644 index 0000000..c9092fa --- /dev/null +++ b/test/background/operators/impls/SelectTabPrevOperator.test.ts @@ -0,0 +1,35 @@ +import { expect } from "chai"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import SelectTabPrevOperator from "../../../../src/background/operators/impls/SelectTabPrevOperator"; + +describe("SelectTabPrevOperator", () => { + describe("#run", () => { + it("select a left tab of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + + const sut = new SelectTabPrevOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/1"); + }); + }); + + describe("#run", () => { + it("select a left tab of the current tab in rotation", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: true }); + await tabPresenter.create("https://example.com/2", { active: false }); + await tabPresenter.create("https://example.com/3", { active: false }); + + const sut = new SelectTabPrevOperator(tabPresenter); + await sut.run(); + + const url = (await tabPresenter.getCurrent()).url; + expect(url).to.equal("https://example.com/3"); + }); + }); +}); diff --git a/test/background/operators/impls/ShowAddBookmarkOperator.test.ts b/test/background/operators/impls/ShowAddBookmarkOperator.test.ts new file mode 100644 index 0000000..1e083c2 --- /dev/null +++ b/test/background/operators/impls/ShowAddBookmarkOperator.test.ts @@ -0,0 +1,50 @@ +import sinon from "sinon"; +import ShowAddBookmarkOperator from "../../../../src/background/operators/impls/ShowAddBookmarkOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("ShowAddBookmarkOperator", () => { + describe("#run", () => { + it("show command with addbookmark command", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "addbookmark "); + + const sut = new ShowAddBookmarkOperator( + tabPresenter, + consoleClient, + false + ); + await sut.run(); + + mock.verify(); + }); + + it("show command with addbookmark command and an URL of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "addbookmark welcome, world"); + + const sut = new ShowAddBookmarkOperator( + tabPresenter, + consoleClient, + true + ); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ShowBufferCommandOperator.test.ts b/test/background/operators/impls/ShowBufferCommandOperator.test.ts new file mode 100644 index 0000000..91455b3 --- /dev/null +++ b/test/background/operators/impls/ShowBufferCommandOperator.test.ts @@ -0,0 +1,25 @@ +import sinon from "sinon"; +import ShowBufferCommandOperator from "../../../../src/background/operators/impls/ShowBufferCommandOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("ShowBufferCommandOperator", () => { + describe("#run", () => { + it("show command with buffer command", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "buffer "); + + const sut = new ShowBufferCommandOperator(tabPresenter, consoleClient); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ShowCommandOperator.test.ts b/test/background/operators/impls/ShowCommandOperator.test.ts new file mode 100644 index 0000000..83b028c --- /dev/null +++ b/test/background/operators/impls/ShowCommandOperator.test.ts @@ -0,0 +1,25 @@ +import sinon from "sinon"; +import ShowCommandOperator from "../../../../src/background/operators/impls/ShowCommandOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("ShowCommandOperator", () => { + describe("#run", () => { + it("show command with addbookmark command", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, ""); + + const sut = new ShowCommandOperator(tabPresenter, consoleClient); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ShowOpenCommandOperator.test.ts b/test/background/operators/impls/ShowOpenCommandOperator.test.ts new file mode 100644 index 0000000..2c2105a --- /dev/null +++ b/test/background/operators/impls/ShowOpenCommandOperator.test.ts @@ -0,0 +1,50 @@ +import sinon from "sinon"; +import ShowOpenCommandOperator from "../../../../src/background/operators/impls/ShowOpenCommandOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("ShowOpenCommandOperator", () => { + describe("#run", () => { + it("show command with open command", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "open "); + + const sut = new ShowOpenCommandOperator( + tabPresenter, + consoleClient, + false + ); + await sut.run(); + + mock.verify(); + }); + + it("show command with open command and an URL of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "open https://example.com/2"); + + const sut = new ShowOpenCommandOperator( + tabPresenter, + consoleClient, + true + ); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ShowTabOpenCommandOperator.test.ts b/test/background/operators/impls/ShowTabOpenCommandOperator.test.ts new file mode 100644 index 0000000..e291d05 --- /dev/null +++ b/test/background/operators/impls/ShowTabOpenCommandOperator.test.ts @@ -0,0 +1,50 @@ +import sinon from "sinon"; +import ShowTabOpenCommandOperator from "../../../../src/background/operators/impls/ShowTabOpenCommandOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("ShowTabOpenCommandOperator", () => { + describe("#run", () => { + it("show command with tabopen command", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "tabopen "); + + const sut = new ShowTabOpenCommandOperator( + tabPresenter, + consoleClient, + false + ); + await sut.run(); + + mock.verify(); + }); + + it("show command with tabopen command and an URL of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "tabopen https://example.com/2"); + + const sut = new ShowTabOpenCommandOperator( + tabPresenter, + consoleClient, + true + ); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ShowWinOpenCommandOperator.test.ts b/test/background/operators/impls/ShowWinOpenCommandOperator.test.ts new file mode 100644 index 0000000..c81a2d4 --- /dev/null +++ b/test/background/operators/impls/ShowWinOpenCommandOperator.test.ts @@ -0,0 +1,50 @@ +import sinon from "sinon"; +import ShowWinOpenCommandOperator from "../../../../src/background/operators/impls/ShowWinOpenCommandOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("ShowWinOpenCommandOperator", () => { + describe("#run", () => { + it("show command with winopen command", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "winopen "); + + const sut = new ShowWinOpenCommandOperator( + tabPresenter, + consoleClient, + false + ); + await sut.run(); + + mock.verify(); + }); + + it("show command with winopen command and an URL of the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon + .mock(consoleClient) + .expects("showCommand") + .withArgs(1, "winopen https://example.com/2"); + + const sut = new ShowWinOpenCommandOperator( + tabPresenter, + consoleClient, + true + ); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/StartFindOperator.test.ts b/test/background/operators/impls/StartFindOperator.test.ts new file mode 100644 index 0000000..7764520 --- /dev/null +++ b/test/background/operators/impls/StartFindOperator.test.ts @@ -0,0 +1,22 @@ +import sinon from "sinon"; +import StartFindOperator from "../../../../src/background/operators/impls/StartFindOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("StartFindOperator", () => { + describe("#run", () => { + it("show find console", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/1", { active: false }); + await tabPresenter.create("https://example.com/2", { active: true }); + await tabPresenter.create("https://example.com/3", { active: false }); + const consoleClient = new MockConsoleClient(); + const mock = sinon.mock(consoleClient).expects("showFind").withArgs(1); + + const sut = new StartFindOperator(tabPresenter, consoleClient); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/TabOperatorFactoryChain.test.ts b/test/background/operators/impls/TabOperatorFactoryChain.test.ts new file mode 100644 index 0000000..7ab5de0 --- /dev/null +++ b/test/background/operators/impls/TabOperatorFactoryChain.test.ts @@ -0,0 +1,71 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import TabOperatorFactoryChain from "../../../../src/background/operators/impls/TabOperatorFactoryChain"; +import MockTabPresenter from "../../mock/MockTabPresenter"; +import DuplicateTabOperator from "../../../../src/background/operators/impls/DuplicateTabOperator"; +import TogglePinnedTabOperator from "../../../../src/background/operators/impls/TogglePinnedTabOperator"; +import UnpinTabOperator from "../../../../src/background/operators/impls/UnpinTabOperator"; +import PinTabOperator from "../../../../src/background/operators/impls/PinTabOperator"; +import ReloadTabOperator from "../../../../src/background/operators/impls/ReloadTabOperator"; +import SelectPreviousSelectedTabOperator from "../../../../src/background/operators/impls/SelectPreviousSelectedTabOperator"; +import SelectLastTabOperator from "../../../../src/background/operators/impls/SelectLastTabOperator"; +import SelectFirstTabOperator from "../../../../src/background/operators/impls/SelectFirstTabOperator"; +import SelectTabNextOperator from "../../../../src/background/operators/impls/SelectTabNextOperator"; +import SelectTabPrevOperator from "../../../../src/background/operators/impls/SelectTabPrevOperator"; +import ReopenTabOperator from "../../../../src/background/operators/impls/ReopenTabOperator"; +import CloseTabOperator from "../../../../src/background/operators/impls/CloseTabOperator"; +import CloseTabRightOperator from "../../../../src/background/operators/impls/CloseTabRightOperator"; +import * as operations from "../../../../src/shared/operations"; + +describe("TabOperatorFactoryChain", () => { + describe("#create", () => { + it("returns a operator for the operation", async () => { + const tabPresenter = new MockTabPresenter(); + const sut = new TabOperatorFactoryChain(tabPresenter); + + expect(sut.create({ type: operations.TAB_CLOSE })).to.be.instanceOf( + CloseTabOperator + ); + expect(sut.create({ type: operations.TAB_CLOSE_RIGHT })).to.be.instanceOf( + CloseTabRightOperator + ); + expect(sut.create({ type: operations.TAB_CLOSE_FORCE })).to.be.instanceOf( + CloseTabOperator + ); + expect(sut.create({ type: operations.TAB_REOPEN })).to.be.instanceOf( + ReopenTabOperator + ); + expect(sut.create({ type: operations.TAB_PREV })).to.be.instanceOf( + SelectTabPrevOperator + ); + expect(sut.create({ type: operations.TAB_NEXT })).to.be.instanceOf( + SelectTabNextOperator + ); + expect(sut.create({ type: operations.TAB_FIRST })).to.be.instanceOf( + SelectFirstTabOperator + ); + expect( + sut.create({ type: operations.TAB_LAST, newTab: false }) + ).to.be.instanceOf(SelectLastTabOperator); + expect( + sut.create({ type: operations.TAB_PREV_SEL, newTab: false }) + ).to.be.instanceOf(SelectPreviousSelectedTabOperator); + expect( + sut.create({ type: operations.TAB_RELOAD, cache: false }) + ).to.be.instanceOf(ReloadTabOperator); + expect(sut.create({ type: operations.TAB_PIN })).to.be.instanceOf( + PinTabOperator + ); + expect(sut.create({ type: operations.TAB_UNPIN })).to.be.instanceOf( + UnpinTabOperator + ); + expect( + sut.create({ type: operations.TAB_TOGGLE_PINNED }) + ).to.be.instanceOf(TogglePinnedTabOperator); + expect(sut.create({ type: operations.TAB_DUPLICATE })).to.be.instanceOf( + DuplicateTabOperator + ); + expect(sut.create({ type: operations.CANCEL })).to.be.null; + }); + }); +}); diff --git a/test/background/operators/impls/TogglePinnedTabOperator.test.ts b/test/background/operators/impls/TogglePinnedTabOperator.test.ts new file mode 100644 index 0000000..f155f83 --- /dev/null +++ b/test/background/operators/impls/TogglePinnedTabOperator.test.ts @@ -0,0 +1,32 @@ +import { expect } from "chai"; +import TogglePinnedTabOperator from "../../../../src/background/operators/impls/TogglePinnedTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("TogglePinnedTabOperator", () => { + describe("#run", () => { + it("toggle pinned to the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/", { + active: true, + pinned: false, + }); + await tabPresenter.create("https://example.com/", { + active: false, + pinned: false, + }); + const sut = new TogglePinnedTabOperator(tabPresenter); + + await sut.run(); + expect((await tabPresenter.getAll()).map((t) => t.pinned)).to.deep.equal([ + true, + false, + ]); + + await sut.run(); + expect((await tabPresenter.getAll()).map((t) => t.pinned)).to.deep.equal([ + false, + false, + ]); + }); + }); +}); diff --git a/test/background/operators/impls/UnpinTabOperator.test.ts b/test/background/operators/impls/UnpinTabOperator.test.ts new file mode 100644 index 0000000..745f48c --- /dev/null +++ b/test/background/operators/impls/UnpinTabOperator.test.ts @@ -0,0 +1,25 @@ +import { expect } from "chai"; +import UnpinTabOperator from "../../../../src/background/operators/impls/UnpinTabOperator"; +import MockTabPresenter from "../../mock/MockTabPresenter"; + +describe("UnpinTabOperator", () => { + describe("#run", () => { + it("make unpinned to the current tab", async () => { + const tabPresenter = new MockTabPresenter(); + await tabPresenter.create("https://example.com/", { + active: true, + pinned: true, + }); + await tabPresenter.create("https://example.com/", { + active: false, + pinned: true, + }); + const sut = new UnpinTabOperator(tabPresenter); + + await sut.run(); + + const pins = (await tabPresenter.getAll()).map((t) => t.pinned); + expect(pins).to.deep.equal([false, true]); + }); + }); +}); diff --git a/test/background/operators/impls/ZoomInOperator.test.ts b/test/background/operators/impls/ZoomInOperator.test.ts new file mode 100644 index 0000000..097e760 --- /dev/null +++ b/test/background/operators/impls/ZoomInOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import ZoomInOperator from "../../../../src/background/operators/impls/ZoomInOperator"; +import MockZoomPresenter from "../../mock/MockZoomPresenter"; + +describe("ZoomInOperator", () => { + describe("#run", () => { + it("zoom-out the current tab", async () => { + const zoomPresenter = new MockZoomPresenter(); + const mock = sinon.mock(zoomPresenter).expects("zoomIn").once(); + + const sut = new ZoomInOperator(zoomPresenter); + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/background/operators/impls/ZoomOperatorFactoryChain.test.ts b/test/background/operators/impls/ZoomOperatorFactoryChain.test.ts new file mode 100644 index 0000000..10c1cee --- /dev/null +++ b/test/background/operators/impls/ZoomOperatorFactoryChain.test.ts @@ -0,0 +1,28 @@ +import "reflect-metadata"; +import { expect } from "chai"; +import ZoomOperatorFactoryChain from "../../../../src/background/operators/impls/ZoomOperatorFactoryChain"; +import MockZoomPresenter from "../../mock/MockZoomPresenter"; +import ZoomInOperator from "../../../../src/background/operators/impls/ZoomInOperator"; +import ZoomOutOperator from "../../../../src/background/operators/impls/ZoomOutOperator"; +import ResetZoomOperator from "../../../../src/background/operators/impls/ResetZoomOperator"; +import * as operations from "../../../../src/shared/operations"; + +describe("ZoomOperatorFactoryChain", () => { + describe("#create", () => { + it("returns a operator for the operation", async () => { + const zoomPresenter = new MockZoomPresenter(); + const sut = new ZoomOperatorFactoryChain(zoomPresenter); + + expect(sut.create({ type: operations.ZOOM_IN })).to.be.instanceOf( + ZoomInOperator + ); + expect(sut.create({ type: operations.ZOOM_OUT })).to.be.instanceOf( + ZoomOutOperator + ); + expect(sut.create({ type: operations.ZOOM_NEUTRAL })).to.be.instanceOf( + ResetZoomOperator + ); + expect(sut.create({ type: operations.CANCEL })).to.be.null; + }); + }); +}); diff --git a/test/background/operators/impls/ZoomOutOperator.test.ts b/test/background/operators/impls/ZoomOutOperator.test.ts new file mode 100644 index 0000000..e0bbcd9 --- /dev/null +++ b/test/background/operators/impls/ZoomOutOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import ZoomOutOperator from "../../../../src/background/operators/impls/ZoomOutOperator"; +import MockZoomPresenter from "../../mock/MockZoomPresenter"; + +describe("ZoomOutOperator", () => { + describe("#run", () => { + it("zoom-in the current tab", async () => { + const zoomPresenter = new MockZoomPresenter(); + const mock = sinon.mock(zoomPresenter).expects("zoomOut").once(); + + const sut = new ZoomOutOperator(zoomPresenter); + await sut.run(); + + mock.verify(); + }); + }); +}); -- cgit v1.2.3 From 18d3a6411753e97cd49b71b41db7bda8055a2762 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 5 Dec 2020 09:56:40 +0900 Subject: Remove unused classes --- src/background/di.ts | 2 +- .../operators/impls/ResetZoomOperator.ts | 2 +- src/background/operators/impls/ZoomInOperator.ts | 2 +- .../operators/impls/ZoomOperatorFactoryChain.ts | 2 +- src/background/operators/impls/ZoomOutOperator.ts | 2 +- src/background/presenters/ZoomPresenter.ts | 60 +++++++ src/background/usecases/AddonEnabledUseCase.ts | 2 +- src/background/usecases/CommandUseCase.ts | 2 +- src/background/usecases/ConsoleUseCase.ts | 65 -------- src/background/usecases/FindUseCase.ts | 17 +- src/background/usecases/NavigateUseCase.ts | 58 ------- src/background/usecases/TabSelectUseCase.ts | 51 ------ src/background/usecases/TabUseCase.ts | 105 ------------ src/background/usecases/ZoomPresenter.ts | 60 ------- src/background/usecases/ZoomUseCase.ts | 51 ------ test/background/mock/MockZoomPresenter.ts | 2 +- test/background/usecases/NavigateUseCase.test.ts | 185 --------------------- 17 files changed, 70 insertions(+), 598 deletions(-) create mode 100644 src/background/presenters/ZoomPresenter.ts delete mode 100644 src/background/usecases/ConsoleUseCase.ts delete mode 100644 src/background/usecases/NavigateUseCase.ts delete mode 100644 src/background/usecases/TabSelectUseCase.ts delete mode 100644 src/background/usecases/TabUseCase.ts delete mode 100644 src/background/usecases/ZoomPresenter.ts delete mode 100644 src/background/usecases/ZoomUseCase.ts delete mode 100644 test/background/usecases/NavigateUseCase.test.ts (limited to 'test') diff --git a/src/background/di.ts b/src/background/di.ts index 9ec3c74..efdf363 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -16,7 +16,7 @@ import { NavigateClientImpl } from "./clients/NavigateClient"; import { ConsoleClientImpl } from "./infrastructures/ConsoleClient"; import { BrowserSettingRepositoryImpl } from "./repositories/BrowserSettingRepository"; import { RepeatRepositoryImpl } from "./repositories/RepeatRepository"; -import { ZoomPresenterImpl } from "./usecases/ZoomPresenter"; +import { ZoomPresenterImpl } from "./presenters/ZoomPresenter"; import { WindowPresenterImpl } from "./presenters/WindowPresenter"; container.register("LocalSettingRepository", { diff --git a/src/background/operators/impls/ResetZoomOperator.ts b/src/background/operators/impls/ResetZoomOperator.ts index 48db1d5..96af733 100644 --- a/src/background/operators/impls/ResetZoomOperator.ts +++ b/src/background/operators/impls/ResetZoomOperator.ts @@ -1,5 +1,5 @@ import Operator from "../Operator"; -import ZoomPresenter from "../../usecases/ZoomPresenter"; +import ZoomPresenter from "../../presenters/ZoomPresenter"; export default class ResetZoomOperator implements Operator { constructor(private readonly zoomPresenter: ZoomPresenter) {} diff --git a/src/background/operators/impls/ZoomInOperator.ts b/src/background/operators/impls/ZoomInOperator.ts index 9ed1861..e900f0d 100644 --- a/src/background/operators/impls/ZoomInOperator.ts +++ b/src/background/operators/impls/ZoomInOperator.ts @@ -1,5 +1,5 @@ import Operator from "../Operator"; -import ZoomPresenter from "../../usecases/ZoomPresenter"; +import ZoomPresenter from "../../presenters/ZoomPresenter"; export default class ZoomInOperator implements Operator { constructor(private readonly zoomPresenter: ZoomPresenter) {} diff --git a/src/background/operators/impls/ZoomOperatorFactoryChain.ts b/src/background/operators/impls/ZoomOperatorFactoryChain.ts index ebcf2a5..bf930a7 100644 --- a/src/background/operators/impls/ZoomOperatorFactoryChain.ts +++ b/src/background/operators/impls/ZoomOperatorFactoryChain.ts @@ -4,7 +4,7 @@ import OperatorFactoryChain from "../OperatorFactoryChain"; import ZoomInOperator from "./ZoomInOperator"; import ZoomOutOperator from "./ZoomOutOperator"; import ResetZoomOperator from "./ResetZoomOperator"; -import ZoomPresenter from "../../usecases/ZoomPresenter"; +import ZoomPresenter from "../../presenters/ZoomPresenter"; import * as operations from "../../../shared/operations"; @injectable() diff --git a/src/background/operators/impls/ZoomOutOperator.ts b/src/background/operators/impls/ZoomOutOperator.ts index 35f5d3d..0c0389e 100644 --- a/src/background/operators/impls/ZoomOutOperator.ts +++ b/src/background/operators/impls/ZoomOutOperator.ts @@ -1,5 +1,5 @@ import Operator from "../Operator"; -import ZoomPresenter from "../../usecases/ZoomPresenter"; +import ZoomPresenter from "../../presenters/ZoomPresenter"; export default class ZoomOutOperator implements Operator { constructor(private readonly zoomPresenter: ZoomPresenter) {} diff --git a/src/background/presenters/ZoomPresenter.ts b/src/background/presenters/ZoomPresenter.ts new file mode 100644 index 0000000..5a3c64d --- /dev/null +++ b/src/background/presenters/ZoomPresenter.ts @@ -0,0 +1,60 @@ +const ZOOM_SETTINGS = [ + 0.33, + 0.5, + 0.66, + 0.75, + 0.8, + 0.9, + 1.0, + 1.1, + 1.25, + 1.5, + 1.75, + 2.0, + 2.5, + 3.0, +] as const; + +export default interface ZoomPresenter { + zoomIn(): Promise; + zoomOut(): Promise; + resetZoom(): Promise; +} + +export class ZoomPresenterImpl implements ZoomPresenter { + async zoomIn(): Promise { + const tab = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + const tabId = tab[0].id as number; + const current = await browser.tabs.getZoom(tabId); + const factor = ZOOM_SETTINGS.find((f) => f > current); + if (factor) { + return browser.tabs.setZoom(tabId, factor); + } + } + + async zoomOut(): Promise { + const tab = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + const tabId = tab[0].id as number; + const current = await browser.tabs.getZoom(tabId); + const factor = ZOOM_SETTINGS.slice(0) + .reverse() + .find((f) => f < current); + if (factor) { + return browser.tabs.setZoom(tabId, factor); + } + } + + async resetZoom(): Promise { + const tab = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + return browser.tabs.setZoom(tab[0].id, 1); + } +} diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts index f563ab0..f9bafde 100644 --- a/src/background/usecases/AddonEnabledUseCase.ts +++ b/src/background/usecases/AddonEnabledUseCase.ts @@ -22,7 +22,7 @@ export default class AddonEnabledUseCase { return this.indicatorPresentor.indicate(enabled); } - onIndicatorClick(tabId: number): Promise { + private onIndicatorClick(tabId: number): Promise { return this.contentMessageClient.toggleAddonEnabled(tabId); } diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts index cadcad1..18ddd4d 100644 --- a/src/background/usecases/CommandUseCase.ts +++ b/src/background/usecases/CommandUseCase.ts @@ -12,7 +12,7 @@ import ContentMessageClient from "../infrastructures/ContentMessageClient"; import RepeatUseCase from "../usecases/RepeatUseCase"; @injectable() -export default class CommandIndicator { +export default class CommandUseCase { constructor( @inject("TabPresenter") private readonly tabPresenter: TabPresenter, diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts deleted file mode 100644 index 4adba65..0000000 --- a/src/background/usecases/ConsoleUseCase.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import TabPresenter from "../presenters/TabPresenter"; -import ConsoleClient from "../infrastructures/ConsoleClient"; - -@injectable() -export default class ConsoleUseCase { - constructor( - @inject("TabPresenter") - private readonly tabPresenter: TabPresenter, - @inject("ConsoleClient") - private readonly consoleClient: ConsoleClient - ) {} - - async showCommand(): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showCommand(tab.id as number, ""); - } - - async showOpenCommand(alter: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - let command = "open "; - if (alter) { - command += tab.url || ""; - } - return this.consoleClient.showCommand(tab.id as number, command); - } - - async showTabopenCommand(alter: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - let command = "tabopen "; - if (alter) { - command += tab.url || ""; - } - return this.consoleClient.showCommand(tab.id as number, command); - } - - async showWinopenCommand(alter: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - let command = "winopen "; - if (alter) { - command += tab.url || ""; - } - return this.consoleClient.showCommand(tab.id as number, command); - } - - async showBufferCommand(): Promise { - const tab = await this.tabPresenter.getCurrent(); - const command = "buffer "; - return this.consoleClient.showCommand(tab.id as number, command); - } - - async showAddbookmarkCommand(alter: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - let command = "addbookmark "; - if (alter) { - command += tab.title || ""; - } - return this.consoleClient.showCommand(tab.id as number, command); - } - - async hideConsole(): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.hide(tab.id as number); - } -} diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts index 404fb48..ce96e03 100644 --- a/src/background/usecases/FindUseCase.ts +++ b/src/background/usecases/FindUseCase.ts @@ -1,17 +1,9 @@ -import { inject, injectable } from "tsyringe"; +import { injectable } from "tsyringe"; import FindRepository from "../repositories/FindRepository"; -import TabPresenter from "../presenters/TabPresenter"; -import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class FindUseCase { - constructor( - @inject("TabPresenter") - private readonly tabPresenter: TabPresenter, - private readonly findRepository: FindRepository, - @inject("ConsoleClient") - private readonly consoleClient: ConsoleClient - ) {} + constructor(private readonly findRepository: FindRepository) {} getKeyword(): Promise { return this.findRepository.getKeyword(); @@ -20,9 +12,4 @@ export default class FindUseCase { setKeyword(keyword: string): Promise { return this.findRepository.setKeyword(keyword); } - - async findStart(): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showFind(tab.id as number); - } } diff --git a/src/background/usecases/NavigateUseCase.ts b/src/background/usecases/NavigateUseCase.ts deleted file mode 100644 index 29e629a..0000000 --- a/src/background/usecases/NavigateUseCase.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import NavigateClient from "../clients/NavigateClient"; -import TabPresenter from "../presenters/TabPresenter"; - -@injectable() -export default class NavigateUseCase { - constructor( - @inject("TabPresenter") - private readonly tabPresenter: TabPresenter, - @inject("NavigateClient") - private readonly navigateClient: NavigateClient - ) {} - - async openHistoryNext(): Promise { - const tab = await this.tabPresenter.getCurrent(); - await this.navigateClient.historyNext(tab.id!); - } - - async openHistoryPrev(): Promise { - const tab = await this.tabPresenter.getCurrent(); - await this.navigateClient.historyPrev(tab.id!); - } - - async openLinkNext(): Promise { - const tab = await this.tabPresenter.getCurrent(); - await this.navigateClient.linkNext(tab.id!); - } - - async openLinkPrev(): Promise { - const tab = await this.tabPresenter.getCurrent(); - await this.navigateClient.linkPrev(tab.id!); - } - - async openParent(): Promise { - const tab = await this.tabPresenter.getCurrent(); - const url = new URL(tab.url!); - if (url.hash.length > 0) { - url.hash = ""; - } else if (url.search.length > 0) { - url.search = ""; - } else { - const basenamePattern = /\/[^/]+$/; - const lastDirPattern = /\/[^/]+\/$/; - if (basenamePattern.test(url.pathname)) { - url.pathname = url.pathname.replace(basenamePattern, "/"); - } else if (lastDirPattern.test(url.pathname)) { - url.pathname = url.pathname.replace(lastDirPattern, "/"); - } - } - await this.tabPresenter.open(url.href); - } - - async openRoot(): Promise { - const tab = await this.tabPresenter.getCurrent(); - const url = new URL(tab.url!); - await this.tabPresenter.open(url.origin); - } -} diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts deleted file mode 100644 index 663ceb8..0000000 --- a/src/background/usecases/TabSelectUseCase.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import TabPresenter from "../presenters/TabPresenter"; - -@injectable() -export default class TabSelectUseCase { - constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} - - async selectPrev(count: number): Promise { - const tabs = await this.tabPresenter.getAll(); - if (tabs.length < 2) { - return; - } - const tab = tabs.find((t) => t.active); - if (!tab) { - return; - } - const select = (tab.index - count + tabs.length) % tabs.length; - return this.tabPresenter.select(tabs[select].id as number); - } - - async selectNext(count: number): Promise { - const tabs = await this.tabPresenter.getAll(); - if (tabs.length < 2) { - return; - } - const tab = tabs.find((t) => t.active); - if (!tab) { - return; - } - const select = (tab.index + count) % tabs.length; - return this.tabPresenter.select(tabs[select].id as number); - } - - async selectFirst(): Promise { - const tabs = await this.tabPresenter.getAll(); - return this.tabPresenter.select(tabs[0].id as number); - } - - async selectLast(): Promise { - const tabs = await this.tabPresenter.getAll(); - return this.tabPresenter.select(tabs[tabs.length - 1].id as number); - } - - async selectPrevSelected(): Promise { - const tabId = await this.tabPresenter.getLastSelectedId(); - if (tabId === null || typeof tabId === "undefined") { - return Promise.resolve(); - } - return this.tabPresenter.select(tabId); - } -} diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts deleted file mode 100644 index be01032..0000000 --- a/src/background/usecases/TabUseCase.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import TabPresenter from "../presenters/TabPresenter"; -import WindowPresenter from "../presenters/WindowPresenter"; -import BrowserSettingRepository from "../repositories/BrowserSettingRepository"; - -@injectable() -export default class TabUseCase { - constructor( - @inject("TabPresenter") - private readonly tabPresenter: TabPresenter, - @inject("WindowPresenter") - private readonly windowPresenter: WindowPresenter, - @inject("BrowserSettingRepository") - private readonly browserSettingRepository: BrowserSettingRepository - ) {} - - async close(force: boolean, selectLeft = false): Promise { - const tab = await this.tabPresenter.getCurrent(); - if (!force && tab.pinned) { - return Promise.resolve(); - } - if (selectLeft && tab.index > 0) { - const tabs = await this.tabPresenter.getAll(); - await this.tabPresenter.select(tabs[tab.index - 1].id as number); - } - return this.tabPresenter.remove([tab.id as number]); - } - - async closeRight(): Promise { - const tabs = await this.tabPresenter.getAll(); - tabs.sort((t1, t2) => t1.index - t2.index); - const index = tabs.findIndex((t) => t.active); - if (index < 0) { - return; - } - for (let i = index + 1; i < tabs.length; ++i) { - const tab = tabs[i]; - if (!tab.pinned) { - this.tabPresenter.remove([tab.id as number]); - } - } - } - - reopen(): Promise { - return this.tabPresenter.reopen(); - } - - async reload(cache: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.reload(tab.id as number, cache); - } - - async setPinned(pinned: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setPinned(tab.id as number, pinned); - } - - async togglePinned(): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setPinned(tab.id as number, !tab.pinned); - } - - async duplicate(): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.duplicate(tab.id as number); - } - - async openPageSource(): Promise { - const tab = await this.tabPresenter.getCurrent(); - const url = "view-source:" + tab.url; - return this.tabPresenter.create(url); - } - - async openHome(newTab: boolean): Promise { - const tab = await this.tabPresenter.getCurrent(); - const urls = await this.browserSettingRepository.getHomepageUrls(); - if (urls.length === 1 && urls[0] === "about:home") { - // eslint-disable-next-line max-len - throw new Error( - "Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs" - ); - } - if (urls.length === 1 && !newTab) { - return this.tabPresenter.open(urls[0], tab.id); - } - for (const url of urls) { - this.tabPresenter.create(url); - } - } - - async openURL( - url: string, - newTab?: boolean, - newWindow?: boolean - ): Promise { - if (newWindow) { - await this.windowPresenter.create(url); - } else if (newTab) { - await this.tabPresenter.create(url); - } else { - const tab = await this.tabPresenter.getCurrent(); - await this.tabPresenter.open(url, tab.id); - } - } -} diff --git a/src/background/usecases/ZoomPresenter.ts b/src/background/usecases/ZoomPresenter.ts deleted file mode 100644 index 5a3c64d..0000000 --- a/src/background/usecases/ZoomPresenter.ts +++ /dev/null @@ -1,60 +0,0 @@ -const ZOOM_SETTINGS = [ - 0.33, - 0.5, - 0.66, - 0.75, - 0.8, - 0.9, - 1.0, - 1.1, - 1.25, - 1.5, - 1.75, - 2.0, - 2.5, - 3.0, -] as const; - -export default interface ZoomPresenter { - zoomIn(): Promise; - zoomOut(): Promise; - resetZoom(): Promise; -} - -export class ZoomPresenterImpl implements ZoomPresenter { - async zoomIn(): Promise { - const tab = await browser.tabs.query({ - active: true, - currentWindow: true, - }); - const tabId = tab[0].id as number; - const current = await browser.tabs.getZoom(tabId); - const factor = ZOOM_SETTINGS.find((f) => f > current); - if (factor) { - return browser.tabs.setZoom(tabId, factor); - } - } - - async zoomOut(): Promise { - const tab = await browser.tabs.query({ - active: true, - currentWindow: true, - }); - const tabId = tab[0].id as number; - const current = await browser.tabs.getZoom(tabId); - const factor = ZOOM_SETTINGS.slice(0) - .reverse() - .find((f) => f < current); - if (factor) { - return browser.tabs.setZoom(tabId, factor); - } - } - - async resetZoom(): Promise { - const tab = await browser.tabs.query({ - active: true, - currentWindow: true, - }); - return browser.tabs.setZoom(tab[0].id, 1); - } -} diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts deleted file mode 100644 index 173e4d7..0000000 --- a/src/background/usecases/ZoomUseCase.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import TabPresenter from "../presenters/TabPresenter"; - -const ZOOM_SETTINGS: number[] = [ - 0.33, - 0.5, - 0.66, - 0.75, - 0.8, - 0.9, - 1.0, - 1.1, - 1.25, - 1.5, - 1.75, - 2.0, - 2.5, - 3.0, -]; - -@injectable() -export default class ZoomUseCase { - constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} - - async zoomIn(): Promise { - const tab = await this.tabPresenter.getCurrent(); - const tabId = tab.id as number; - const current = await this.tabPresenter.getZoom(tabId); - const factor = ZOOM_SETTINGS.find((f) => f > current); - if (factor) { - return this.tabPresenter.setZoom(tabId as number, factor); - } - } - - async zoomOut(): Promise { - const tab = await this.tabPresenter.getCurrent(); - const tabId = tab.id as number; - const current = await this.tabPresenter.getZoom(tabId); - const factor = ZOOM_SETTINGS.slice(0) - .reverse() - .find((f) => f < current); - if (factor) { - return this.tabPresenter.setZoom(tabId as number, factor); - } - } - - async zoomNutoral(): Promise { - const tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setZoom(tab.id as number, 1); - } -} diff --git a/test/background/mock/MockZoomPresenter.ts b/test/background/mock/MockZoomPresenter.ts index a1ca100..53d1980 100644 --- a/test/background/mock/MockZoomPresenter.ts +++ b/test/background/mock/MockZoomPresenter.ts @@ -1,4 +1,4 @@ -import ZoomPresenter from "../../../src/background/usecases/ZoomPresenter"; +import ZoomPresenter from "../../../src/background/presenters/ZoomPresenter"; export default class MockZoomPresenter implements ZoomPresenter { resetZoom(): Promise { diff --git a/test/background/usecases/NavigateUseCase.test.ts b/test/background/usecases/NavigateUseCase.test.ts deleted file mode 100644 index f1b94a7..0000000 --- a/test/background/usecases/NavigateUseCase.test.ts +++ /dev/null @@ -1,185 +0,0 @@ -import "reflect-metadata"; -import TabPresenter from "../../../src/background/presenters/TabPresenter"; -import NavigateUseCase from "../../../src/background/usecases/NavigateUseCase"; -import NavigateClient, { - NavigateClientImpl, -} from "../../../src/background/clients/NavigateClient"; -import * as sinon from "sinon"; - -class MockTabPresenter implements TabPresenter { - create(_url: string, _opts?: unknown): Promise { - throw new Error("not implemented"); - } - - duplicate(_id: number): Promise { - throw new Error("not implemented"); - } - - getAll(): Promise { - throw new Error("not implemented"); - } - - getByKeyword( - _keyword: string, - _excludePinned: boolean - ): Promise { - throw new Error("not implemented"); - } - - getCurrent(): Promise { - throw new Error("not implemented"); - } - - getLastSelectedId(): Promise { - throw new Error("not implemented"); - } - - getZoom(_tabId: number): Promise { - throw new Error("not implemented"); - } - - onSelected( - _listener: (arg: { tabId: number; windowId: number }) => void - ): void { - throw new Error("not implemented"); - } - - open(_url: string, _tabId?: number): Promise { - throw new Error("not implemented"); - } - - reload(_tabId: number, _cache: boolean): Promise { - throw new Error("not implemented"); - } - - remove(_ids: number[]): Promise { - throw new Error("not implemented"); - } - - reopen(): Promise { - throw new Error("not implemented"); - } - - select(_tabId: number): Promise { - throw new Error("not implemented"); - } - - setPinned(_tabId: number, _pinned: boolean): Promise { - throw new Error("not implemented"); - } - - setZoom(_tabId: number, _factor: number): Promise { - throw new Error("not implemented"); - } -} - -describe("NavigateUseCase", () => { - let sut: NavigateUseCase; - let tabPresenter: TabPresenter; - let navigateClient: NavigateClient; - - beforeEach(() => { - tabPresenter = new MockTabPresenter(); - navigateClient = new NavigateClientImpl(); - sut = new NavigateUseCase(tabPresenter, navigateClient); - }); - - const newTab = (url: string): browser.tabs.Tab => { - return { - index: 0, - title: "dummy title", - url: url, - active: true, - hidden: false, - highlighted: false, - incognito: false, - isArticle: false, - isInReaderMode: false, - lastAccessed: 1585446733000, - pinned: false, - selected: false, - windowId: 0, - }; - }; - - describe("#openParent()", async () => { - it("opens parent directory of file", async () => { - sinon - .stub(tabPresenter, "getCurrent") - .returns( - Promise.resolve(newTab("https://google.com/fruits/yellow/banana")) - ); - - const mock = sinon - .mock(tabPresenter) - .expects("open") - .withArgs("https://google.com/fruits/yellow/"); - - await sut.openParent(); - - mock.verify(); - }); - - it("opens parent directory of directory", async () => { - sinon - .stub(tabPresenter, "getCurrent") - .returns(Promise.resolve(newTab("https://google.com/fruits/yellow/"))); - - const mock = sinon - .mock(tabPresenter) - .expects("open") - .withArgs("https://google.com/fruits/"); - - await sut.openParent(); - - mock.verify(); - }); - - it("removes hash", async () => { - sinon - .stub(tabPresenter, "getCurrent") - .returns(Promise.resolve(newTab("https://google.com/#top"))); - - const mock = sinon - .mock(tabPresenter) - .expects("open") - .withArgs("https://google.com/"); - - await sut.openParent(); - - mock.verify(); - }); - - it("removes search query", async () => { - sinon - .stub(tabPresenter, "getCurrent") - .returns(Promise.resolve(newTab("https://google.com/search?q=apple"))); - - const mock = sinon - .mock(tabPresenter) - .expects("open") - .withArgs("https://google.com/search"); - - await sut.openParent(); - - mock.verify(); - }); - }); - - describe("#openRoot()", () => { - it("opens root direectory", async () => { - sinon - .stub(tabPresenter, "getCurrent") - .returns(Promise.resolve(newTab("https://google.com/seach?q=apple"))); - - const mock = sinon - .mock(tabPresenter) - .expects("open") - .withArgs("https://google.com"); - - await sut.openRoot(); - - mock.verify(); - }); - }); -}); -- cgit v1.2.3