From 410ffbb0376b9399928ef8d4dd13079bfb120e14 Mon Sep 17 00:00:00 2001 From: Shin'ya UEOKA Date: Fri, 4 Oct 2019 04:01:35 +0000 Subject: [PATCH] Make Keymap class --- .../infrastructures/ContentMessageListener.ts | 5 +- .../repositories/SettingRepository.ts | 8 ++- src/content/client/SettingClient.ts | 4 +- src/content/usecases/KeymapUseCase.ts | 21 +++--- src/settings/actions/index.ts | 8 +-- src/settings/actions/setting.ts | 6 +- src/settings/components/index.tsx | 12 ++-- src/settings/reducers/setting.ts | 6 +- src/shared/SettingData.ts | 53 ++++++++------- src/shared/Settings.ts | 27 ++++---- src/shared/settings/Keymaps.ts | 37 +++++++++++ .../repositories/SettingRepository.test.ts | 6 +- test/shared/SettingData.test.ts | 48 +++++++++----- test/shared/Settings.test.ts | 45 +++---------- test/shared/settings/Keymaps.test.ts | 66 +++++++++++++++++++ 15 files changed, 223 insertions(+), 129 deletions(-) create mode 100644 src/shared/settings/Keymaps.ts create mode 100644 test/shared/settings/Keymaps.test.ts diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index 3d24741..f348a74 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -8,6 +8,7 @@ import AddonEnabledController from '../controllers/AddonEnabledController'; import LinkController from '../controllers/LinkController'; import OperationController from '../controllers/OperationController'; import MarkController from '../controllers/MarkController'; +import { toJSON } from '../../shared/Settings'; @injectable() export default class ContentMessageListener { @@ -101,8 +102,8 @@ export default class ContentMessageListener { return this.commandController.exec(text); } - onSettingsQuery(): Promise { - return this.settingController.getSetting(); + async onSettingsQuery(): Promise { + return toJSON(await this.settingController.getSetting()); } onFindGetKeyword(): Promise { diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts index 2f159e5..c7a0e84 100644 --- a/src/background/repositories/SettingRepository.ts +++ b/src/background/repositories/SettingRepository.ts @@ -1,6 +1,6 @@ import { injectable } from 'tsyringe'; import MemoryStorage from '../infrastructures/MemoryStorage'; -import Settings from '../../shared/Settings'; +import Settings, { valueOf, toJSON } from '../../shared/Settings'; import * as PropertyDefs from '../../shared/property-defs'; const CACHED_SETTING_KEY = 'setting'; @@ -14,11 +14,13 @@ export default class SettingRepository { } get(): Promise { - return Promise.resolve(this.cache.get(CACHED_SETTING_KEY)); + let data = this.cache.get(CACHED_SETTING_KEY); + return Promise.resolve(valueOf(data)); } update(value: Settings): void { - return this.cache.set(CACHED_SETTING_KEY, value); + let data = toJSON(value); + return this.cache.set(CACHED_SETTING_KEY, data); } async setProperty( diff --git a/src/content/client/SettingClient.ts b/src/content/client/SettingClient.ts index 0850f11..a7cd1ee 100644 --- a/src/content/client/SettingClient.ts +++ b/src/content/client/SettingClient.ts @@ -1,4 +1,4 @@ -import Settings from '../../shared/Settings'; +import Settings, { valueOf } from '../../shared/Settings'; import * as messages from '../../shared/messages'; export default interface SettingClient { @@ -10,6 +10,6 @@ export class SettingClientImpl { let settings = await browser.runtime.sendMessage({ type: messages.SETTINGS_QUERY, }); - return settings as Settings; + return valueOf(settings); } } diff --git a/src/content/usecases/KeymapUseCase.ts b/src/content/usecases/KeymapUseCase.ts index 0f654c8..62cd04c 100644 --- a/src/content/usecases/KeymapUseCase.ts +++ b/src/content/usecases/KeymapUseCase.ts @@ -3,16 +3,16 @@ import KeymapRepository from '../repositories/KeymapRepository'; import SettingRepository from '../repositories/SettingRepository'; import AddonEnabledRepository from '../repositories/AddonEnabledRepository'; import * as operations from '../../shared/operations'; -import { Keymaps } from '../../shared/Settings'; import Key from '../domains/Key'; import KeySequence from '../domains/KeySequence'; +import Keymaps from '../../shared/settings/Keymaps'; type KeymapEntityMap = Map; -const reservedKeymaps: Keymaps = { +const reservedKeymaps = Keymaps.fromJSON({ '': { type: operations.CANCEL }, '': { type: operations.CANCEL }, -}; +}); @injectable() export default class KeymapUseCase { @@ -65,16 +65,11 @@ export default class KeymapUseCase { } private keymapEntityMap(): KeymapEntityMap { - let keymaps = { - ...this.settingRepository.get().keymaps, - ...reservedKeymaps, - }; - let entries = Object.entries(keymaps).map((entry) => { - return [ - KeySequence.fromMapKeys(entry[0]), - entry[1], - ]; - }) as [KeySequence, operations.Operation][]; + let keymaps = this.settingRepository.get().keymaps.combine(reservedKeymaps); + let entries = keymaps.entries().map(entry => [ + KeySequence.fromMapKeys(entry[0]), + entry[1], + ]) as [KeySequence, operations.Operation][]; return new Map(entries); } } diff --git a/src/settings/actions/index.ts b/src/settings/actions/index.ts index b1e996e..dfa41c4 100644 --- a/src/settings/actions/index.ts +++ b/src/settings/actions/index.ts @@ -1,5 +1,5 @@ import { - JSONSettings, FormSettings, SettingSource, + JSONTextSettings, FormSettings, SettingSource, } from '../../shared/SettingData'; // Settings @@ -11,14 +11,14 @@ export const SETTING_SWITCH_TO_JSON = 'setting.switch.to.json'; interface SettingSetSettingsAcion { type: typeof SETTING_SET_SETTINGS; source: SettingSource; - json?: JSONSettings; + json?: JSONTextSettings; form?: FormSettings; } interface SettingShowErrorAction { type: typeof SETTING_SHOW_ERROR; error: string; - json: JSONSettings; + json: JSONTextSettings; } interface SettingSwitchToFormAction { @@ -28,7 +28,7 @@ interface SettingSwitchToFormAction { interface SettingSwitchToJsonAction { type: typeof SETTING_SWITCH_TO_JSON; - json: JSONSettings, + json: JSONTextSettings, } export type SettingAction = diff --git a/src/settings/actions/setting.ts b/src/settings/actions/setting.ts index 9eb416e..9404791 100644 --- a/src/settings/actions/setting.ts +++ b/src/settings/actions/setting.ts @@ -1,7 +1,7 @@ import * as actions from './index'; import * as storages from '../storage'; import SettingData, { - JSONSettings, FormSettings, SettingSource, + JSONTextSettings, FormSettings, SettingSource, } from '../../shared/SettingData'; const load = async(): Promise => { @@ -26,7 +26,7 @@ const save = async(data: SettingData): Promise => { return set(data); }; -const switchToForm = (json: JSONSettings): actions.SettingAction => { +const switchToForm = (json: JSONTextSettings): actions.SettingAction => { try { // toSettings exercise validation let form = FormSettings.fromSettings(json.toSettings()); @@ -44,7 +44,7 @@ const switchToForm = (json: JSONSettings): actions.SettingAction => { }; const switchToJson = (form: FormSettings): actions.SettingAction => { - let json = JSONSettings.fromSettings(form.toSettings()); + let json = JSONTextSettings.fromSettings(form.toSettings()); return { type: actions.SETTING_SWITCH_TO_JSON, json, diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index eeac2cf..ada6efb 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -8,7 +8,7 @@ import BlacklistForm from './form/BlacklistForm'; import PropertiesForm from './form/PropertiesForm'; import * as settingActions from '../../settings/actions/setting'; import SettingData, { - JSONSettings, FormKeymaps, FormSearch, FormSettings, + JSONTextSettings, FormKeymaps, FormSearch, FormSettings, } from '../../shared/SettingData'; import { State as AppState } from '../reducers/setting'; import * as settings from '../../shared/Settings'; @@ -75,7 +75,7 @@ class SettingsComponent extends React.Component { ; } - renderJsonFields(json: JSONSettings, error: string) { + renderJsonFields(json: JSONTextSettings, error: string) { return
{ error={error} onValueChange={this.bindJson.bind(this)} onBlur={this.save.bind(this)} - value={json.toJSON()} + value={json.toJSONText()} />
; } @@ -97,7 +97,7 @@ class SettingsComponent extends React.Component { fields = this.renderFormFields(this.props.form); } else if (this.props.source === 'json') { fields = this.renderJsonFields( - this.props.json as JSONSettings, this.props.error); + this.props.json as JSONTextSettings, this.props.error); } return (
@@ -165,7 +165,7 @@ class SettingsComponent extends React.Component { bindJson(_name: string, value: string) { let data = new SettingData({ source: this.props.source, - json: JSONSettings.valueOf(value), + json: JSONTextSettings.fromText(value), }); this.props.dispatch(settingActions.set(data)); } @@ -183,7 +183,7 @@ class SettingsComponent extends React.Component { return; } this.props.dispatch( - settingActions.switchToForm(this.props.json as JSONSettings)); + settingActions.switchToForm(this.props.json as JSONTextSettings)); this.save(); } } diff --git a/src/settings/reducers/setting.ts b/src/settings/reducers/setting.ts index c4a21c7..89bf1cb 100644 --- a/src/settings/reducers/setting.ts +++ b/src/settings/reducers/setting.ts @@ -1,18 +1,18 @@ import * as actions from '../actions'; import { - JSONSettings, FormSettings, SettingSource, + JSONTextSettings, FormSettings, SettingSource, } from '../../shared/SettingData'; export interface State { source: SettingSource; - json?: JSONSettings; + json?: JSONTextSettings; form?: FormSettings; error: string; } const defaultState: State = { source: SettingSource.JSON, - json: JSONSettings.valueOf(''), + json: JSONTextSettings.fromText(''), error: '', }; diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index 14a7d35..eb83b75 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -1,5 +1,6 @@ import * as operations from './operations'; import Settings, * as settings from './Settings'; +import Keymaps from './settings/Keymaps'; export class FormKeymaps { private data: {[op: string]: string}; @@ -8,8 +9,8 @@ export class FormKeymaps { this.data = data; } - toKeymaps(): settings.Keymaps { - let keymaps: settings.Keymaps = {}; + toKeymaps(): Keymaps { + let keymaps: { [key: string]: operations.Operation } = {}; for (let name of Object.keys(this.data)) { let [type, argStr] = name.split('?'); let args = {}; @@ -19,7 +20,7 @@ export class FormKeymaps { let key = this.data[name]; keymaps[key] = operations.valueOf({ type, ...args }); } - return keymaps; + return Keymaps.fromJSON(keymaps); } toJSON(): {[op: string]: string} { @@ -42,10 +43,11 @@ export class FormKeymaps { return new FormKeymaps(data); } - static fromKeymaps(keymaps: settings.Keymaps): FormKeymaps { + static fromKeymaps(keymaps: Keymaps): FormKeymaps { + let json = keymaps.toJSON(); let data: {[op: string]: string} = {}; - for (let key of Object.keys(keymaps)) { - let op = keymaps[key]; + for (let key of Object.keys(json)) { + let op = json[key]; let args = { ...op }; delete args.type; @@ -109,27 +111,32 @@ export class FormSearch { } } -export class JSONSettings { - private json: string; - - constructor(json: any) { - this.json = json; +export class JSONTextSettings { + constructor( + private json: string, + ) { } toSettings(): Settings { return settings.valueOf(JSON.parse(this.json)); } - toJSON(): string { + toJSONText(): string { return this.json; } - static valueOf(o: ReturnType): JSONSettings { - return new JSONSettings(o); + static fromText(o: string): JSONTextSettings { + return new JSONTextSettings(o); } - static fromSettings(data: Settings): JSONSettings { - return new JSONSettings(JSON.stringify(data, undefined, 2)); + static fromSettings(data: Settings): JSONTextSettings { + let json = { + keymaps: data.keymaps.toJSON(), + search: data.search, + properties: data.properties, + blacklist: data.blacklist, + }; + return new JSONTextSettings(JSON.stringify(json, undefined, 2)); } } @@ -192,7 +199,7 @@ export class FormSettings { toSettings(): Settings { return settings.valueOf({ - keymaps: this.keymaps.toKeymaps(), + keymaps: this.keymaps.toKeymaps().toJSON(), search: this.search.toSearchSettings(), properties: this.properties, blacklist: this.blacklist, @@ -244,7 +251,7 @@ export enum SettingSource { export default class SettingData { private source: SettingSource; - private json?: JSONSettings; + private json?: JSONTextSettings; private form?: FormSettings; @@ -252,7 +259,7 @@ export default class SettingData { source, json, form }: { source: SettingSource, - json?: JSONSettings, + json?: JSONTextSettings, form?: FormSettings, }) { this.source = source; @@ -264,7 +271,7 @@ export default class SettingData { return this.source; } - getJSON(): JSONSettings { + getJSON(): JSONTextSettings { if (!this.json) { throw new TypeError('json settings not set'); } @@ -283,7 +290,7 @@ export default class SettingData { case SettingSource.JSON: return { source: this.source, - json: (this.json as JSONSettings).toJSON(), + json: (this.json as JSONTextSettings).toJSONText(), }; case SettingSource.Form: return { @@ -313,8 +320,8 @@ export default class SettingData { case SettingSource.JSON: return new SettingData({ source: o.source, - json: JSONSettings.valueOf( - o.json as ReturnType), + json: JSONTextSettings.fromText( + o.json as ReturnType), }); case SettingSource.Form: return new SettingData({ diff --git a/src/shared/Settings.ts b/src/shared/Settings.ts index d338e2a..3014abc 100644 --- a/src/shared/Settings.ts +++ b/src/shared/Settings.ts @@ -1,7 +1,5 @@ -import * as operations from './operations'; import * as PropertyDefs from './property-defs'; - -export type Keymaps = {[key: string]: operations.Operation}; +import Keymaps from './settings/Keymaps'; export interface Search { default: string; @@ -21,14 +19,6 @@ export default interface Settings { blacklist: string[]; } -export const keymapsValueOf = (o: any): Keymaps => { - return Object.keys(o).reduce((keymaps: Keymaps, key: string): Keymaps => { - let op = operations.valueOf(o[key]); - keymaps[key] = op; - return keymaps; - }, {}); -}; - export const searchValueOf = (o: any): Search => { if (typeof o.default !== 'string') { throw new TypeError('string field "default" not set"'); @@ -97,7 +87,7 @@ export const valueOf = (o: any): Settings => { for (let key of Object.keys(o)) { switch (key) { case 'keymaps': - settings.keymaps = keymapsValueOf(o.keymaps); + settings.keymaps = Keymaps.fromJSON(o.keymaps); break; case 'search': settings.search = searchValueOf(o.search); @@ -115,8 +105,17 @@ export const valueOf = (o: any): Settings => { return settings; }; +export const toJSON = (settings: Settings): any => { + return { + keymaps: settings.keymaps.toJSON(), + search: settings.search, + properties: settings.properties, + blacklist: settings.blacklist, + }; +}; + export const DefaultSetting: Settings = { - keymaps: { + keymaps: Keymaps.fromJSON({ '0': { 'type': 'scroll.home' }, ':': { 'type': 'command.show' }, 'o': { 'type': 'command.show.open', 'alter': false }, @@ -179,7 +178,7 @@ export const DefaultSetting: Settings = { 'N': { 'type': 'find.prev' }, '.': { 'type': 'repeat.last' }, '': { 'type': 'addon.toggle.enabled' } - }, + }), search: { default: 'google', engines: { diff --git a/src/shared/settings/Keymaps.ts b/src/shared/settings/Keymaps.ts new file mode 100644 index 0000000..a5558b0 --- /dev/null +++ b/src/shared/settings/Keymaps.ts @@ -0,0 +1,37 @@ +import * as operations from '../operations'; + +export type KeymapsJSON = { [key: string]: operations.Operation }; + +export default class Keymaps { + constructor( + private readonly data: KeymapsJSON, + ) { + } + + static fromJSON(json: any): Keymaps { + if (typeof json !== 'object' || json === null) { + throw new TypeError('invalid keymaps type: ' + JSON.stringify(json)); + } + + let data: KeymapsJSON = {}; + for (let key of Object.keys(json)) { + data[key] = operations.valueOf(json[key]); + } + return new Keymaps(data); + } + + combine(other: Keymaps): Keymaps { + return new Keymaps({ + ...this.data, + ...other.data, + }); + } + + toJSON(): KeymapsJSON { + return this.data; + } + + entries(): [string, operations.Operation][] { + return Object.entries(this.data); + } +} diff --git a/test/content/repositories/SettingRepository.test.ts b/test/content/repositories/SettingRepository.test.ts index fea70b7..457ca4c 100644 --- a/test/content/repositories/SettingRepository.test.ts +++ b/test/content/repositories/SettingRepository.test.ts @@ -1,12 +1,13 @@ import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository'; import { expect } from 'chai'; +import Keymaps from '../../../src/shared/settings/Keymaps'; describe('SettingRepositoryImpl', () => { it('updates and gets current value', () => { let sut = new SettingRepositoryImpl(); let settings = { - keymaps: {}, + keymaps: Keymaps.fromJSON({}), search: { default: 'google', engines: { @@ -19,7 +20,7 @@ describe('SettingRepositoryImpl', () => { complete: 'sbh', }, blacklist: [], - } + }; sut.set(settings); @@ -27,4 +28,3 @@ describe('SettingRepositoryImpl', () => { expect(actual.properties.hintchars).to.equal('abcd1234'); }); }); - diff --git a/test/shared/SettingData.test.ts b/test/shared/SettingData.test.ts index 8736ecb..9567f76 100644 --- a/test/shared/SettingData.test.ts +++ b/test/shared/SettingData.test.ts @@ -1,8 +1,9 @@ import SettingData, { - FormKeymaps, JSONSettings, FormSettings, + FormKeymaps, JSONTextSettings, FormSettings, } from '../../src/shared/SettingData'; -import Settings, { Keymaps } from '../../src/shared/Settings'; +import Settings from '../../src/shared/Settings'; import { expect } from 'chai'; +import Keymaps from '../../src/shared/settings/Keymaps'; describe('shared/SettingData', () => { describe('FormKeymaps', () => { @@ -11,9 +12,9 @@ describe('shared/SettingData', () => { let data = { 'scroll.vertically?{"count":1}': 'j', 'scroll.home': '0', - } + }; - let keymaps = FormKeymaps.valueOf(data).toKeymaps(); + let keymaps = FormKeymaps.valueOf(data).toKeymaps().toJSON(); expect(keymaps).to.deep.equal({ 'j': { type: 'scroll.vertically', count: 1 }, '0': { type: 'scroll.home' }, @@ -23,13 +24,13 @@ describe('shared/SettingData', () => { describe('#fromKeymaps to #toJSON', () => { it('create from a Keymaps and create a JSON object', () => { - let data: Keymaps = { + let keymaps: Keymaps = Keymaps.fromJSON({ 'j': { type: 'scroll.vertically', count: 1 }, '0': { type: 'scroll.home' }, - } + }); - let keymaps = FormKeymaps.fromKeymaps(data).toJSON(); - expect(keymaps).to.deep.equal({ + let form = FormKeymaps.fromKeymaps(keymaps).toJSON(); + expect(form).to.deep.equal({ 'scroll.vertically?{"count":1}': 'j', 'scroll.home': '0', }); @@ -56,15 +57,20 @@ describe('shared/SettingData', () => { "blacklist": [] }`; - let settings = JSONSettings.valueOf(o).toSettings(); - expect(settings).to.deep.equal(JSON.parse(o)); + let settings = JSONTextSettings.fromText(o).toSettings(); + expect({ + keymaps: settings.keymaps.toJSON(), + search: settings.search, + properties: settings.properties, + blacklist: settings.blacklist, + }).to.deep.equal(JSON.parse(o)); }); }); describe('#fromSettings to #toJSON', () => { it('create from a Settings and create a JSON string', () => { let o = { - keymaps: {}, + keymaps: Keymaps.fromJSON({}), search: { default: "google", engines: { @@ -79,8 +85,13 @@ describe('shared/SettingData', () => { blacklist: [], }; - let json = JSONSettings.fromSettings(o).toJSON(); - expect(JSON.parse(json)).to.deep.equal(o); + let json = JSONTextSettings.fromSettings(o).toJSONText(); + expect(JSON.parse(json)).to.deep.equal({ + keymaps: o.keymaps.toJSON(), + search: o.search, + properties: o.properties, + blacklist: o.blacklist, + }); }); }); }); @@ -108,7 +119,12 @@ describe('shared/SettingData', () => { }; let settings = FormSettings.valueOf(data).toSettings(); - expect(settings).to.deep.equal({ + expect({ + keymaps: settings.keymaps.toJSON(), + search: settings.search, + properties: settings.properties, + blacklist: settings.blacklist, + }).to.deep.equal({ keymaps: { 'j': { type: 'scroll.vertically', count: 1 }, '0': { type: 'scroll.home' }, @@ -132,10 +148,10 @@ describe('shared/SettingData', () => { describe('#fromSettings to #toJSON', () => { it('create from a Settings and create a JSON string', () => { let data: Settings = { - keymaps: { + keymaps: Keymaps.fromJSON({ 'j': { type: 'scroll.vertically', count: 1 }, '0': { type: 'scroll.home' }, - }, + }), search: { default: "google", engines: { diff --git a/test/shared/Settings.test.ts b/test/shared/Settings.test.ts index 04b28c4..9faf9d1 100644 --- a/test/shared/Settings.test.ts +++ b/test/shared/Settings.test.ts @@ -1,31 +1,7 @@ import * as settings from '../../src/shared/Settings'; -import { expect } from 'chai'; +import {expect} from 'chai'; describe('Settings', () => { - describe('#keymapsValueOf', () => { - it('returns empty object by empty settings', () => { - let keymaps = settings.keymapsValueOf({}); - expect(keymaps).to.be.empty; - }); - - it('returns keymaps by valid settings', () => { - let keymaps = settings.keymapsValueOf({ - k: { type: "scroll.vertically", count: -1 }, - j: { type: "scroll.vertically", count: 1 }, - }); - - expect(keymaps['k']).to.deep.equal({ type: "scroll.vertically", count: -1 }); - expect(keymaps['j']).to.deep.equal({ type: "scroll.vertically", count: 1 }); - }); - - it('throws a TypeError by invalid settings', () => { - expect(() => settings.keymapsValueOf(null)).to.throw(TypeError); - expect(() => settings.keymapsValueOf({ - k: { type: "invalid.operation" }, - })).to.throw(TypeError); - }); - }); - describe('#searchValueOf', () => { it('returns search settings by valid settings', () => { let search = settings.searchValueOf({ @@ -110,16 +86,6 @@ describe('Settings', () => { complete: "sbh" }); }); - - it('throws a TypeError by invalid settings', () => { - expect(() => settings.keymapsValueOf(null)).to.throw(TypeError); - expect(() => settings.keymapsValueOf({ - smoothscroll: 'false', - })).to.throw(TypeError); - expect(() => settings.keymapsValueOf({ - unknown: 'xyz' - })).to.throw(TypeError); - }); }); describe('#blacklistValueOf', () => { @@ -161,7 +127,12 @@ describe('Settings', () => { "blacklist": [] }); - expect(x).to.deep.equal({ + expect({ + keymaps: x.keymaps.toJSON(), + search: x.search, + properties: x.properties, + blacklist: x.blacklist, + }).to.deep.equal({ keymaps: {}, search: { default: "google", @@ -180,7 +151,7 @@ describe('Settings', () => { it('sets default settings', () => { let value = settings.valueOf({}); - expect(value.keymaps).to.not.be.empty; + expect(value.keymaps.toJSON()).to.not.be.empty; expect(value.properties).to.not.be.empty; expect(value.search.default).to.be.a('string'); expect(value.search.engines).to.be.an('object'); diff --git a/test/shared/settings/Keymaps.test.ts b/test/shared/settings/Keymaps.test.ts new file mode 100644 index 0000000..7896a63 --- /dev/null +++ b/test/shared/settings/Keymaps.test.ts @@ -0,0 +1,66 @@ +import Keymaps from '../../../src/shared/settings/Keymaps'; +import { expect } from 'chai'; + +describe('Keymaps', () => { + describe('#valueOf', () => { + it('returns empty object by empty settings', () => { + let keymaps = Keymaps.fromJSON({}).toJSON(); + expect(keymaps).to.be.empty; + }); + + it('returns keymaps by valid settings', () => { + let keymaps = Keymaps.fromJSON({ + k: { type: "scroll.vertically", count: -1 }, + j: { type: "scroll.vertically", count: 1 }, + }).toJSON(); + + expect(keymaps['k']).to.deep.equal({ type: "scroll.vertically", count: -1 }); + expect(keymaps['j']).to.deep.equal({ type: "scroll.vertically", count: 1 }); + }); + + it('throws a TypeError by invalid settings', () => { + expect(() => Keymaps.fromJSON(null)).to.throw(TypeError); + expect(() => Keymaps.fromJSON({ + k: { type: "invalid.operation" }, + })).to.throw(TypeError); + }); + }); + + describe('#combine', () => { + it('returns combined keymaps', () => { + let keymaps = Keymaps.fromJSON({ + k: { type: "scroll.vertically", count: -1 }, + j: { type: "scroll.vertically", count: 1 }, + }).combine(Keymaps.fromJSON({ + n: { type: "find.next" }, + N: { type: "find.prev" }, + })); + + let entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2)); + expect(entries).deep.equals([ + ['j', { type: "scroll.vertically", count: 1 }], + ['k', { type: "scroll.vertically", count: -1 }], + ['n', { type: "find.next" }], + ['N', { type: "find.prev" }], + ]); + }); + + it('overrides current keymaps', () => { + let keymaps = Keymaps.fromJSON({ + k: { type: "scroll.vertically", count: -1 }, + j: { type: "scroll.vertically", count: 1 }, + }).combine(Keymaps.fromJSON({ + n: { type: "find.next" }, + j: { type: "find.prev" }, + })); + + let entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2)); + expect(entries).deep.equals([ + ['j', { type: "find.prev" }], + ['k', { type: "scroll.vertically", count: -1 }], + ['n', { type: "find.next" }], + ]); + }); + }); +}); +