From c60d0e7392fc708e961614d6b756a045de74f458 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 30 Apr 2019 14:00:07 +0900 Subject: Rename .js/.jsx to .ts/.tsx --- test/background/domains/GlobalMark.test.js | 11 -- test/background/domains/GlobalMark.test.ts | 11 ++ .../infrastructures/MemoryStorage.test.js | 44 ------ .../infrastructures/MemoryStorage.test.ts | 44 ++++++ test/background/repositories/Mark.test.js | 26 ---- test/background/repositories/Mark.test.ts | 26 ++++ test/background/repositories/Version.js | 34 ----- test/background/repositories/Version.ts | 34 +++++ test/background/usecases/filters.test.js | 113 -------------- test/background/usecases/filters.test.ts | 113 ++++++++++++++ test/background/usecases/parsers.test.js | 47 ------ test/background/usecases/parsers.test.ts | 47 ++++++ test/console/actions/console.test.js | 70 --------- test/console/actions/console.test.ts | 70 +++++++++ .../console/components/console/Completion.test.jsx | 168 --------------------- .../console/components/console/Completion.test.tsx | 168 +++++++++++++++++++++ test/console/reducers/console.test.js | 131 ---------------- test/console/reducers/console.test.ts | 131 ++++++++++++++++ test/content/actions/follow-controller.test.js | 34 ----- test/content/actions/follow-controller.test.ts | 34 +++++ test/content/actions/input.test.js | 19 --- test/content/actions/input.test.ts | 19 +++ test/content/actions/mark.test.js | 35 ----- test/content/actions/mark.test.ts | 35 +++++ test/content/actions/setting.test.js | 35 ----- test/content/actions/setting.test.ts | 35 +++++ test/content/components/common/follow.test.js | 25 --- test/content/components/common/follow.test.ts | 25 +++ test/content/components/common/hint.test.js | 57 ------- test/content/components/common/hint.test.ts | 57 +++++++ test/content/components/common/input.test.js | 70 --------- test/content/components/common/input.test.ts | 70 +++++++++ test/content/hint-key-producer.test.js | 24 --- test/content/hint-key-producer.test.ts | 24 +++ test/content/navigates.test.js | 137 ----------------- test/content/navigates.test.ts | 137 +++++++++++++++++ test/content/reducers/addon.test.js | 17 --- test/content/reducers/addon.test.ts | 17 +++ test/content/reducers/find.test.js | 22 --- test/content/reducers/find.test.ts | 22 +++ test/content/reducers/follow-controller.test.js | 47 ------ test/content/reducers/follow-controller.test.ts | 47 ++++++ test/content/reducers/input.test.js | 25 --- test/content/reducers/input.test.ts | 25 +++ test/content/reducers/mark.test.js | 41 ----- test/content/reducers/mark.test.ts | 41 +++++ test/content/reducers/setting.test.js | 17 --- test/content/reducers/setting.test.ts | 17 +++ test/main.js | 6 - test/main.ts | 6 + .../components/form/BlacklistForm.test.jsx | 92 ----------- .../components/form/BlacklistForm.test.tsx | 92 +++++++++++ test/settings/components/form/KeymapsForm.test.jsx | 64 -------- test/settings/components/form/KeymapsForm.test.tsx | 64 ++++++++ .../components/form/PropertiesForm.test.jsx | 104 ------------- .../components/form/PropertiesForm.test.tsx | 104 +++++++++++++ .../components/form/SearchEngineForm.test.jsx | 128 ---------------- .../components/form/SearchEngineForm.test.tsx | 128 ++++++++++++++++ test/settings/components/ui/input.test.jsx | 111 -------------- test/settings/components/ui/input.test.tsx | 111 ++++++++++++++ test/settings/reducers/setting.test.js | 55 ------- test/settings/reducers/setting.test.ts | 55 +++++++ test/shared/blacklists.test.js | 49 ------ test/shared/blacklists.test.ts | 49 ++++++ test/shared/settings/validator.test.js | 81 ---------- test/shared/settings/validator.test.ts | 81 ++++++++++ test/shared/settings/values.test.js | 138 ----------------- test/shared/settings/values.test.ts | 138 +++++++++++++++++ test/shared/urls.test.js | 48 ------ test/shared/urls.test.ts | 48 ++++++ test/shared/utils/keys.test.js | 164 -------------------- test/shared/utils/keys.test.ts | 164 ++++++++++++++++++++ test/shared/utils/re.test.js | 19 --- test/shared/utils/re.test.ts | 19 +++ 74 files changed, 2308 insertions(+), 2308 deletions(-) delete mode 100644 test/background/domains/GlobalMark.test.js create mode 100644 test/background/domains/GlobalMark.test.ts delete mode 100644 test/background/infrastructures/MemoryStorage.test.js create mode 100644 test/background/infrastructures/MemoryStorage.test.ts delete mode 100644 test/background/repositories/Mark.test.js create mode 100644 test/background/repositories/Mark.test.ts delete mode 100644 test/background/repositories/Version.js create mode 100644 test/background/repositories/Version.ts delete mode 100644 test/background/usecases/filters.test.js create mode 100644 test/background/usecases/filters.test.ts delete mode 100644 test/background/usecases/parsers.test.js create mode 100644 test/background/usecases/parsers.test.ts delete mode 100644 test/console/actions/console.test.js create mode 100644 test/console/actions/console.test.ts delete mode 100644 test/console/components/console/Completion.test.jsx create mode 100644 test/console/components/console/Completion.test.tsx delete mode 100644 test/console/reducers/console.test.js create mode 100644 test/console/reducers/console.test.ts delete mode 100644 test/content/actions/follow-controller.test.js create mode 100644 test/content/actions/follow-controller.test.ts delete mode 100644 test/content/actions/input.test.js create mode 100644 test/content/actions/input.test.ts delete mode 100644 test/content/actions/mark.test.js create mode 100644 test/content/actions/mark.test.ts delete mode 100644 test/content/actions/setting.test.js create mode 100644 test/content/actions/setting.test.ts delete mode 100644 test/content/components/common/follow.test.js create mode 100644 test/content/components/common/follow.test.ts delete mode 100644 test/content/components/common/hint.test.js create mode 100644 test/content/components/common/hint.test.ts delete mode 100644 test/content/components/common/input.test.js create mode 100644 test/content/components/common/input.test.ts delete mode 100644 test/content/hint-key-producer.test.js create mode 100644 test/content/hint-key-producer.test.ts delete mode 100644 test/content/navigates.test.js create mode 100644 test/content/navigates.test.ts delete mode 100644 test/content/reducers/addon.test.js create mode 100644 test/content/reducers/addon.test.ts delete mode 100644 test/content/reducers/find.test.js create mode 100644 test/content/reducers/find.test.ts delete mode 100644 test/content/reducers/follow-controller.test.js create mode 100644 test/content/reducers/follow-controller.test.ts delete mode 100644 test/content/reducers/input.test.js create mode 100644 test/content/reducers/input.test.ts delete mode 100644 test/content/reducers/mark.test.js create mode 100644 test/content/reducers/mark.test.ts delete mode 100644 test/content/reducers/setting.test.js create mode 100644 test/content/reducers/setting.test.ts delete mode 100644 test/main.js create mode 100644 test/main.ts delete mode 100644 test/settings/components/form/BlacklistForm.test.jsx create mode 100644 test/settings/components/form/BlacklistForm.test.tsx delete mode 100644 test/settings/components/form/KeymapsForm.test.jsx create mode 100644 test/settings/components/form/KeymapsForm.test.tsx delete mode 100644 test/settings/components/form/PropertiesForm.test.jsx create mode 100644 test/settings/components/form/PropertiesForm.test.tsx delete mode 100644 test/settings/components/form/SearchEngineForm.test.jsx create mode 100644 test/settings/components/form/SearchEngineForm.test.tsx delete mode 100644 test/settings/components/ui/input.test.jsx create mode 100644 test/settings/components/ui/input.test.tsx delete mode 100644 test/settings/reducers/setting.test.js create mode 100644 test/settings/reducers/setting.test.ts delete mode 100644 test/shared/blacklists.test.js create mode 100644 test/shared/blacklists.test.ts delete mode 100644 test/shared/settings/validator.test.js create mode 100644 test/shared/settings/validator.test.ts delete mode 100644 test/shared/settings/values.test.js create mode 100644 test/shared/settings/values.test.ts delete mode 100644 test/shared/urls.test.js create mode 100644 test/shared/urls.test.ts delete mode 100644 test/shared/utils/keys.test.js create mode 100644 test/shared/utils/keys.test.ts delete mode 100644 test/shared/utils/re.test.js create mode 100644 test/shared/utils/re.test.ts (limited to 'test') diff --git a/test/background/domains/GlobalMark.test.js b/test/background/domains/GlobalMark.test.js deleted file mode 100644 index ed636e9..0000000 --- a/test/background/domains/GlobalMark.test.js +++ /dev/null @@ -1,11 +0,0 @@ -import GlobalMark from 'background/domains/GlobalMark'; - -describe('background/domains/global-mark', () => { - describe('constructor and getter', () => { - let mark = new GlobalMark(1, 'http://example.com', 10, 30); - expect(mark.tabId).to.equal(1); - expect(mark.url).to.equal('http://example.com'); - expect(mark.x).to.equal(10); - expect(mark.y).to.equal(30); - }); -}); diff --git a/test/background/domains/GlobalMark.test.ts b/test/background/domains/GlobalMark.test.ts new file mode 100644 index 0000000..ed636e9 --- /dev/null +++ b/test/background/domains/GlobalMark.test.ts @@ -0,0 +1,11 @@ +import GlobalMark from 'background/domains/GlobalMark'; + +describe('background/domains/global-mark', () => { + describe('constructor and getter', () => { + let mark = new GlobalMark(1, 'http://example.com', 10, 30); + expect(mark.tabId).to.equal(1); + expect(mark.url).to.equal('http://example.com'); + expect(mark.x).to.equal(10); + expect(mark.y).to.equal(30); + }); +}); diff --git a/test/background/infrastructures/MemoryStorage.test.js b/test/background/infrastructures/MemoryStorage.test.js deleted file mode 100644 index 95d3780..0000000 --- a/test/background/infrastructures/MemoryStorage.test.js +++ /dev/null @@ -1,44 +0,0 @@ -import MemoryStorage from 'background/infrastructures/MemoryStorage'; - -describe("background/infrastructures/memory-storage", () => { - it('stores values', () => { - let cache = new MemoryStorage(); - cache.set('number', 123); - expect(cache.get('number')).to.equal(123); - - cache.set('string', '123'); - expect(cache.get('string')).to.equal('123'); - - cache.set('object', { hello: '123' }); - expect(cache.get('object')).to.deep.equal({ hello: '123' }); - }); - - it('returns undefined if no keys', () => { - let cache = new MemoryStorage(); - expect(cache.get('no-keys')).to.be.undefined; - }) - - it('stored on shared memory', () => { - let cache = new MemoryStorage(); - cache.set('red', 'apple'); - - cache = new MemoryStorage(); - let got = cache.get('red'); - expect(got).to.equal('apple'); - }); - - it('stored cloned objects', () => { - let cache = new MemoryStorage(); - let recipe = { sugar: '300g' }; - cache.set('recipe', recipe); - - recipe.salt = '20g' - let got = cache.get('recipe', recipe); - expect(got).to.deep.equal({ sugar: '300g' }); - }); - - it('throws an error with unserializable objects', () => { - let cache = new MemoryStorage(); - expect(() => cache.set('fn', setTimeout)).to.throw(); - }) -}); diff --git a/test/background/infrastructures/MemoryStorage.test.ts b/test/background/infrastructures/MemoryStorage.test.ts new file mode 100644 index 0000000..95d3780 --- /dev/null +++ b/test/background/infrastructures/MemoryStorage.test.ts @@ -0,0 +1,44 @@ +import MemoryStorage from 'background/infrastructures/MemoryStorage'; + +describe("background/infrastructures/memory-storage", () => { + it('stores values', () => { + let cache = new MemoryStorage(); + cache.set('number', 123); + expect(cache.get('number')).to.equal(123); + + cache.set('string', '123'); + expect(cache.get('string')).to.equal('123'); + + cache.set('object', { hello: '123' }); + expect(cache.get('object')).to.deep.equal({ hello: '123' }); + }); + + it('returns undefined if no keys', () => { + let cache = new MemoryStorage(); + expect(cache.get('no-keys')).to.be.undefined; + }) + + it('stored on shared memory', () => { + let cache = new MemoryStorage(); + cache.set('red', 'apple'); + + cache = new MemoryStorage(); + let got = cache.get('red'); + expect(got).to.equal('apple'); + }); + + it('stored cloned objects', () => { + let cache = new MemoryStorage(); + let recipe = { sugar: '300g' }; + cache.set('recipe', recipe); + + recipe.salt = '20g' + let got = cache.get('recipe', recipe); + expect(got).to.deep.equal({ sugar: '300g' }); + }); + + it('throws an error with unserializable objects', () => { + let cache = new MemoryStorage(); + expect(() => cache.set('fn', setTimeout)).to.throw(); + }) +}); diff --git a/test/background/repositories/Mark.test.js b/test/background/repositories/Mark.test.js deleted file mode 100644 index 2a5b099..0000000 --- a/test/background/repositories/Mark.test.js +++ /dev/null @@ -1,26 +0,0 @@ -import MarkRepository from 'background/repositories/MarkRepository'; -import GlobalMark from 'background/domains/GlobalMark'; - -describe('background/repositories/mark', () => { - let repository; - - beforeEach(() => { - repository = new MarkRepository; - }); - - it('get and set', async() => { - let mark = new GlobalMark(1, 'http://example.com', 10, 30); - - repository.setMark('A', mark); - - let got = await repository.getMark('A'); - expect(got).to.be.a('object'); - expect(got.tabId).to.equal(1); - expect(got.url).to.equal('http://example.com'); - expect(got.x).to.equal(10); - expect(got.y).to.equal(30); - - got = await repository.getMark('B'); - expect(got).to.be.undefined; - }); -}); diff --git a/test/background/repositories/Mark.test.ts b/test/background/repositories/Mark.test.ts new file mode 100644 index 0000000..2a5b099 --- /dev/null +++ b/test/background/repositories/Mark.test.ts @@ -0,0 +1,26 @@ +import MarkRepository from 'background/repositories/MarkRepository'; +import GlobalMark from 'background/domains/GlobalMark'; + +describe('background/repositories/mark', () => { + let repository; + + beforeEach(() => { + repository = new MarkRepository; + }); + + it('get and set', async() => { + let mark = new GlobalMark(1, 'http://example.com', 10, 30); + + repository.setMark('A', mark); + + let got = await repository.getMark('A'); + expect(got).to.be.a('object'); + expect(got.tabId).to.equal(1); + expect(got.url).to.equal('http://example.com'); + expect(got.x).to.equal(10); + expect(got.y).to.equal(30); + + got = await repository.getMark('B'); + expect(got).to.be.undefined; + }); +}); diff --git a/test/background/repositories/Version.js b/test/background/repositories/Version.js deleted file mode 100644 index c7fa88b..0000000 --- a/test/background/repositories/Version.js +++ /dev/null @@ -1,34 +0,0 @@ -import VersionRepository from 'background/repositories/Version'; - -describe("background/repositories/version", () => { - let versionRepository; - - beforeEach(() => { - versionRepository = new VersionRepository; - }); - - describe('#get', () => { - beforeEach(() => { - return browser.storage.local.remove('version'); - }); - - it('loads saved version', async() => { - await browser.storage.local.set({ version: '1.2.3' }); - let version = await this.versionRepository.get(); - expect(version).to.equal('1.2.3'); - }); - - it('returns undefined if no versions in storage', async() => { - let version = await storage.load(); - expect(version).to.be.a('undefined'); - }); - }); - - describe('#update', () => { - it('saves version string', async() => { - await versionRepository.update('2.3.4'); - let { version } = await browser.storage.local.get('version'); - expect(version).to.equal('2.3.4'); - }); - }); -}); diff --git a/test/background/repositories/Version.ts b/test/background/repositories/Version.ts new file mode 100644 index 0000000..c7fa88b --- /dev/null +++ b/test/background/repositories/Version.ts @@ -0,0 +1,34 @@ +import VersionRepository from 'background/repositories/Version'; + +describe("background/repositories/version", () => { + let versionRepository; + + beforeEach(() => { + versionRepository = new VersionRepository; + }); + + describe('#get', () => { + beforeEach(() => { + return browser.storage.local.remove('version'); + }); + + it('loads saved version', async() => { + await browser.storage.local.set({ version: '1.2.3' }); + let version = await this.versionRepository.get(); + expect(version).to.equal('1.2.3'); + }); + + it('returns undefined if no versions in storage', async() => { + let version = await storage.load(); + expect(version).to.be.a('undefined'); + }); + }); + + describe('#update', () => { + it('saves version string', async() => { + await versionRepository.update('2.3.4'); + let { version } = await browser.storage.local.get('version'); + expect(version).to.equal('2.3.4'); + }); + }); +}); diff --git a/test/background/usecases/filters.test.js b/test/background/usecases/filters.test.js deleted file mode 100644 index bdfb0be..0000000 --- a/test/background/usecases/filters.test.js +++ /dev/null @@ -1,113 +0,0 @@ -import * as filters from 'background/usecases/filters'; - -describe("background/usecases/filters", () => { - describe('filterHttp', () => { - it('filters http URLs duplicates to https hosts', () => { - let pages = [ - { url: 'http://i-beam.org/foo' }, - { url: 'https://i-beam.org/bar' }, - { url: 'http://i-beam.net/hoge' }, - { url: 'http://i-beam.net/fuga' }, - ]; - let filtered = filters.filterHttp(pages); - - let urls = filtered.map(x => x.url); - expect(urls).to.deep.equal([ - 'https://i-beam.org/bar', 'http://i-beam.net/hoge', 'http://i-beam.net/fuga' - ]); - }) - }); - - describe('filterBlankTitle', () => { - it('filters blank titles', () => { - let pages = [ - { title: 'hello' }, - { title: '' }, - {}, - ]; - let filtered = filters.filterBlankTitle(pages); - - expect(filtered).to.deep.equal([{ title: 'hello' }]); - }); - }) - - describe('filterByTailingSlash', () => { - it('filters duplicated pathname on tailing slash', () => { - let pages = [ - { url: 'http://i-beam.org/content' }, - { url: 'http://i-beam.org/content/' }, - { url: 'http://i-beam.org/search' }, - { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - ]; - let filtered = filters.filterByTailingSlash(pages); - - let urls = filtered.map(x => x.url); - expect(urls).to.deep.equal([ - 'http://i-beam.org/content', - 'http://i-beam.org/search', - 'http://i-beam.org/search?q=apple_banana_cherry', - ]); - }); - }) - - describe('filterByPathname', () => { - it('remains items less than minimam length', () => { - let pages = [ - { url: 'http://i-beam.org/search?q=apple' }, - { url: 'http://i-beam.org/search?q=apple_banana' }, - { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - { url: 'http://i-beam.org/request?q=apple' }, - { url: 'http://i-beam.org/request?q=apple_banana' }, - { url: 'http://i-beam.org/request?q=apple_banana_cherry' }, - ]; - let filtered = filters.filterByPathname(pages, 10); - expect(filtered).to.have.lengthOf(6); - }); - - it('filters by length of pathname', () => { - let pages = [ - { url: 'http://i-beam.org/search?q=apple' }, - { url: 'http://i-beam.org/search?q=apple_banana' }, - { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - { url: 'http://i-beam.net/search?q=apple' }, - { url: 'http://i-beam.net/search?q=apple_banana' }, - { url: 'http://i-beam.net/search?q=apple_banana_cherry' }, - ]; - let filtered = filters.filterByPathname(pages, 0); - expect(filtered).to.deep.equal([ - { url: 'http://i-beam.org/search?q=apple' }, - { url: 'http://i-beam.net/search?q=apple' }, - ]); - }); - }) - - describe('filterByOrigin', () => { - it('remains items less than minimam length', () => { - let pages = [ - { url: 'http://i-beam.org/search?q=apple' }, - { url: 'http://i-beam.org/search?q=apple_banana' }, - { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - { url: 'http://i-beam.org/request?q=apple' }, - { url: 'http://i-beam.org/request?q=apple_banana' }, - { url: 'http://i-beam.org/request?q=apple_banana_cherry' }, - ]; - let filtered = filters.filterByOrigin(pages, 10); - expect(filtered).to.have.lengthOf(6); - }); - - it('filters by length of pathname', () => { - let pages = [ - { url: 'http://i-beam.org/search?q=apple' }, - { url: 'http://i-beam.org/search?q=apple_banana' }, - { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - { url: 'http://i-beam.org/request?q=apple' }, - { url: 'http://i-beam.org/request?q=apple_banana' }, - { url: 'http://i-beam.org/request?q=apple_banana_cherry' }, - ]; - let filtered = filters.filterByOrigin(pages, 0); - expect(filtered).to.deep.equal([ - { url: 'http://i-beam.org/search?q=apple' }, - ]); - }); - }) -}); diff --git a/test/background/usecases/filters.test.ts b/test/background/usecases/filters.test.ts new file mode 100644 index 0000000..bdfb0be --- /dev/null +++ b/test/background/usecases/filters.test.ts @@ -0,0 +1,113 @@ +import * as filters from 'background/usecases/filters'; + +describe("background/usecases/filters", () => { + describe('filterHttp', () => { + it('filters http URLs duplicates to https hosts', () => { + let pages = [ + { url: 'http://i-beam.org/foo' }, + { url: 'https://i-beam.org/bar' }, + { url: 'http://i-beam.net/hoge' }, + { url: 'http://i-beam.net/fuga' }, + ]; + let filtered = filters.filterHttp(pages); + + let urls = filtered.map(x => x.url); + expect(urls).to.deep.equal([ + 'https://i-beam.org/bar', 'http://i-beam.net/hoge', 'http://i-beam.net/fuga' + ]); + }) + }); + + describe('filterBlankTitle', () => { + it('filters blank titles', () => { + let pages = [ + { title: 'hello' }, + { title: '' }, + {}, + ]; + let filtered = filters.filterBlankTitle(pages); + + expect(filtered).to.deep.equal([{ title: 'hello' }]); + }); + }) + + describe('filterByTailingSlash', () => { + it('filters duplicated pathname on tailing slash', () => { + let pages = [ + { url: 'http://i-beam.org/content' }, + { url: 'http://i-beam.org/content/' }, + { url: 'http://i-beam.org/search' }, + { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, + ]; + let filtered = filters.filterByTailingSlash(pages); + + let urls = filtered.map(x => x.url); + expect(urls).to.deep.equal([ + 'http://i-beam.org/content', + 'http://i-beam.org/search', + 'http://i-beam.org/search?q=apple_banana_cherry', + ]); + }); + }) + + describe('filterByPathname', () => { + it('remains items less than minimam length', () => { + let pages = [ + { url: 'http://i-beam.org/search?q=apple' }, + { url: 'http://i-beam.org/search?q=apple_banana' }, + { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, + { url: 'http://i-beam.org/request?q=apple' }, + { url: 'http://i-beam.org/request?q=apple_banana' }, + { url: 'http://i-beam.org/request?q=apple_banana_cherry' }, + ]; + let filtered = filters.filterByPathname(pages, 10); + expect(filtered).to.have.lengthOf(6); + }); + + it('filters by length of pathname', () => { + let pages = [ + { url: 'http://i-beam.org/search?q=apple' }, + { url: 'http://i-beam.org/search?q=apple_banana' }, + { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, + { url: 'http://i-beam.net/search?q=apple' }, + { url: 'http://i-beam.net/search?q=apple_banana' }, + { url: 'http://i-beam.net/search?q=apple_banana_cherry' }, + ]; + let filtered = filters.filterByPathname(pages, 0); + expect(filtered).to.deep.equal([ + { url: 'http://i-beam.org/search?q=apple' }, + { url: 'http://i-beam.net/search?q=apple' }, + ]); + }); + }) + + describe('filterByOrigin', () => { + it('remains items less than minimam length', () => { + let pages = [ + { url: 'http://i-beam.org/search?q=apple' }, + { url: 'http://i-beam.org/search?q=apple_banana' }, + { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, + { url: 'http://i-beam.org/request?q=apple' }, + { url: 'http://i-beam.org/request?q=apple_banana' }, + { url: 'http://i-beam.org/request?q=apple_banana_cherry' }, + ]; + let filtered = filters.filterByOrigin(pages, 10); + expect(filtered).to.have.lengthOf(6); + }); + + it('filters by length of pathname', () => { + let pages = [ + { url: 'http://i-beam.org/search?q=apple' }, + { url: 'http://i-beam.org/search?q=apple_banana' }, + { url: 'http://i-beam.org/search?q=apple_banana_cherry' }, + { url: 'http://i-beam.org/request?q=apple' }, + { url: 'http://i-beam.org/request?q=apple_banana' }, + { url: 'http://i-beam.org/request?q=apple_banana_cherry' }, + ]; + let filtered = filters.filterByOrigin(pages, 0); + expect(filtered).to.deep.equal([ + { url: 'http://i-beam.org/search?q=apple' }, + ]); + }); + }) +}); diff --git a/test/background/usecases/parsers.test.js b/test/background/usecases/parsers.test.js deleted file mode 100644 index 17b034b..0000000 --- a/test/background/usecases/parsers.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import * as parsers from 'background/usecases/parsers'; - -describe("shared/commands/parsers", () => { - describe("#parsers.parseSetOption", () => { - it('parse set string', () => { - let [key, value] = parsers.parseSetOption('encoding=utf-8', { encoding: 'string' }); - expect(key).to.equal('encoding'); - expect(value).to.equal('utf-8'); - }); - - it('parse set empty string', () => { - let [key, value] = parsers.parseSetOption('encoding=', { encoding: 'string' }); - expect(key).to.equal('encoding'); - expect(value).to.equal(''); - }); - - it('parse set string', () => { - let [key, value] = parsers.parseSetOption('history=50', { history: 'number' }); - expect(key).to.equal('history'); - expect(value).to.equal(50); - }); - - it('parse set boolean', () => { - let [key, value] = parsers.parseSetOption('paste', { paste: 'boolean' }); - expect(key).to.equal('paste'); - expect(value).to.be.true; - - [key, value] = parsers.parseSetOption('nopaste', { paste: 'boolean' }); - expect(key).to.equal('paste'); - expect(value).to.be.false; - }); - - it('throws error on unknown property', () => { - expect(() => parsers.parseSetOption('charset=utf-8', {})).to.throw(Error, 'Unknown'); - expect(() => parsers.parseSetOption('smoothscroll', {})).to.throw(Error, 'Unknown'); - expect(() => parsers.parseSetOption('nosmoothscroll', {})).to.throw(Error, 'Unknown'); - }) - - it('throws error on invalid property', () => { - expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'number' })).to.throw(Error, 'Not number'); - expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'boolean' })).to.throw(Error, 'Invalid'); - expect(() => parsers.parseSetOption('charset=', { charset: 'boolean' })).to.throw(Error, 'Invalid'); - expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'string' })).to.throw(Error, 'Invalid'); - expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'number' })).to.throw(Error, 'Invalid'); - }) - }); -}); diff --git a/test/background/usecases/parsers.test.ts b/test/background/usecases/parsers.test.ts new file mode 100644 index 0000000..17b034b --- /dev/null +++ b/test/background/usecases/parsers.test.ts @@ -0,0 +1,47 @@ +import * as parsers from 'background/usecases/parsers'; + +describe("shared/commands/parsers", () => { + describe("#parsers.parseSetOption", () => { + it('parse set string', () => { + let [key, value] = parsers.parseSetOption('encoding=utf-8', { encoding: 'string' }); + expect(key).to.equal('encoding'); + expect(value).to.equal('utf-8'); + }); + + it('parse set empty string', () => { + let [key, value] = parsers.parseSetOption('encoding=', { encoding: 'string' }); + expect(key).to.equal('encoding'); + expect(value).to.equal(''); + }); + + it('parse set string', () => { + let [key, value] = parsers.parseSetOption('history=50', { history: 'number' }); + expect(key).to.equal('history'); + expect(value).to.equal(50); + }); + + it('parse set boolean', () => { + let [key, value] = parsers.parseSetOption('paste', { paste: 'boolean' }); + expect(key).to.equal('paste'); + expect(value).to.be.true; + + [key, value] = parsers.parseSetOption('nopaste', { paste: 'boolean' }); + expect(key).to.equal('paste'); + expect(value).to.be.false; + }); + + it('throws error on unknown property', () => { + expect(() => parsers.parseSetOption('charset=utf-8', {})).to.throw(Error, 'Unknown'); + expect(() => parsers.parseSetOption('smoothscroll', {})).to.throw(Error, 'Unknown'); + expect(() => parsers.parseSetOption('nosmoothscroll', {})).to.throw(Error, 'Unknown'); + }) + + it('throws error on invalid property', () => { + expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'number' })).to.throw(Error, 'Not number'); + expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'boolean' })).to.throw(Error, 'Invalid'); + expect(() => parsers.parseSetOption('charset=', { charset: 'boolean' })).to.throw(Error, 'Invalid'); + expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'string' })).to.throw(Error, 'Invalid'); + expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'number' })).to.throw(Error, 'Invalid'); + }) + }); +}); diff --git a/test/console/actions/console.test.js b/test/console/actions/console.test.js deleted file mode 100644 index 10cd9fe..0000000 --- a/test/console/actions/console.test.js +++ /dev/null @@ -1,70 +0,0 @@ -import actions from 'console/actions'; -import * as consoleActions from 'console/actions/console'; - -describe("console actions", () => { - describe('hide', () => { - it('create CONSOLE_HIDE action', () => { - let action = consoleActions.hide(); - expect(action.type).to.equal(actions.CONSOLE_HIDE); - }); - }); - describe("showCommand", () => { - it('create CONSOLE_SHOW_COMMAND action', () => { - let action = consoleActions.showCommand('hello'); - expect(action.type).to.equal(actions.CONSOLE_SHOW_COMMAND); - expect(action.text).to.equal('hello'); - }); - }); - - describe("showFind", () => { - it('create CONSOLE_SHOW_FIND action', () => { - let action = consoleActions.showFind(); - expect(action.type).to.equal(actions.CONSOLE_SHOW_FIND); - }); - }); - - describe("showError", () => { - it('create CONSOLE_SHOW_ERROR action', () => { - let action = consoleActions.showError('an error'); - expect(action.type).to.equal(actions.CONSOLE_SHOW_ERROR); - expect(action.text).to.equal('an error'); - }); - }); - - describe("showInfo", () => { - it('create CONSOLE_SHOW_INFO action', () => { - let action = consoleActions.showInfo('an info'); - expect(action.type).to.equal(actions.CONSOLE_SHOW_INFO); - expect(action.text).to.equal('an info'); - }); - }); - - describe("hideCommand", () => { - it('create CONSOLE_HIDE_COMMAND action', () => { - let action = consoleActions.hideCommand(); - expect(action.type).to.equal(actions.CONSOLE_HIDE_COMMAND); - }); - }); - - describe('setConsoleText', () => { - it('create CONSOLE_SET_CONSOLE_TEXT action', () => { - let action = consoleActions.setConsoleText('hello world'); - expect(action.type).to.equal(actions.CONSOLE_SET_CONSOLE_TEXT); - expect(action.consoleText).to.equal('hello world'); - }); - }); - - describe("completionPrev", () => { - it('create CONSOLE_COMPLETION_PREV action', () => { - let action = consoleActions.completionPrev(); - expect(action.type).to.equal(actions.CONSOLE_COMPLETION_PREV); - }); - }); - - describe("completionNext", () => { - it('create CONSOLE_COMPLETION_NEXT action', () => { - let action = consoleActions.completionNext(); - expect(action.type).to.equal(actions.CONSOLE_COMPLETION_NEXT); - }); - }); -}); diff --git a/test/console/actions/console.test.ts b/test/console/actions/console.test.ts new file mode 100644 index 0000000..10cd9fe --- /dev/null +++ b/test/console/actions/console.test.ts @@ -0,0 +1,70 @@ +import actions from 'console/actions'; +import * as consoleActions from 'console/actions/console'; + +describe("console actions", () => { + describe('hide', () => { + it('create CONSOLE_HIDE action', () => { + let action = consoleActions.hide(); + expect(action.type).to.equal(actions.CONSOLE_HIDE); + }); + }); + describe("showCommand", () => { + it('create CONSOLE_SHOW_COMMAND action', () => { + let action = consoleActions.showCommand('hello'); + expect(action.type).to.equal(actions.CONSOLE_SHOW_COMMAND); + expect(action.text).to.equal('hello'); + }); + }); + + describe("showFind", () => { + it('create CONSOLE_SHOW_FIND action', () => { + let action = consoleActions.showFind(); + expect(action.type).to.equal(actions.CONSOLE_SHOW_FIND); + }); + }); + + describe("showError", () => { + it('create CONSOLE_SHOW_ERROR action', () => { + let action = consoleActions.showError('an error'); + expect(action.type).to.equal(actions.CONSOLE_SHOW_ERROR); + expect(action.text).to.equal('an error'); + }); + }); + + describe("showInfo", () => { + it('create CONSOLE_SHOW_INFO action', () => { + let action = consoleActions.showInfo('an info'); + expect(action.type).to.equal(actions.CONSOLE_SHOW_INFO); + expect(action.text).to.equal('an info'); + }); + }); + + describe("hideCommand", () => { + it('create CONSOLE_HIDE_COMMAND action', () => { + let action = consoleActions.hideCommand(); + expect(action.type).to.equal(actions.CONSOLE_HIDE_COMMAND); + }); + }); + + describe('setConsoleText', () => { + it('create CONSOLE_SET_CONSOLE_TEXT action', () => { + let action = consoleActions.setConsoleText('hello world'); + expect(action.type).to.equal(actions.CONSOLE_SET_CONSOLE_TEXT); + expect(action.consoleText).to.equal('hello world'); + }); + }); + + describe("completionPrev", () => { + it('create CONSOLE_COMPLETION_PREV action', () => { + let action = consoleActions.completionPrev(); + expect(action.type).to.equal(actions.CONSOLE_COMPLETION_PREV); + }); + }); + + describe("completionNext", () => { + it('create CONSOLE_COMPLETION_NEXT action', () => { + let action = consoleActions.completionNext(); + expect(action.type).to.equal(actions.CONSOLE_COMPLETION_NEXT); + }); + }); +}); diff --git a/test/console/components/console/Completion.test.jsx b/test/console/components/console/Completion.test.jsx deleted file mode 100644 index 16bf11a..0000000 --- a/test/console/components/console/Completion.test.jsx +++ /dev/null @@ -1,168 +0,0 @@ -import React from 'react'; -import Completion from 'console/components/console/Completion' -import ReactTestRenderer from 'react-test-renderer'; - -describe("console/components/console/completion", () => { - let completions = [{ - name: "Fruit", - items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], - }, { - name: "Element", - items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], - }]; - - it('renders Completion component', () => { - let root = ReactTestRenderer.create().root; - - expect(root.children).to.have.lengthOf(1); - - let children = root.children[0].children; - expect(children).to.have.lengthOf(8); - expect(children[0].props.title).to.equal('Fruit'); - expect(children[1].props.caption).to.equal('apple'); - expect(children[2].props.caption).to.equal('banana'); - expect(children[3].props.caption).to.equal('cherry'); - expect(children[4].props.title).to.equal('Element'); - expect(children[5].props.caption).to.equal('argon'); - expect(children[6].props.caption).to.equal('boron'); - expect(children[7].props.caption).to.equal('carbon'); - }); - - it('highlight current item', () => { - let root = ReactTestRenderer.create().root; - - let children = root.children[0].children; - expect(children[5].props.highlight).to.be.true; - }); - - it('does not highlight any items', () => { - let root = ReactTestRenderer.create().root; - - let children = root.children[0].children; - for (let li of children[0].children) { - expect(li.props.highlight).not.to.be.ok; - } - }); - - it('limits completion items', () => { - let root = ReactTestRenderer.create().root; - - let children = root.children[0].children; - expect(children).to.have.lengthOf(3); - - expect(children[0].props.title).to.equal('Fruit'); - expect(children[1].props.caption).to.equal('apple'); - expect(children[2].props.caption).to.equal('banana'); - - root = ReactTestRenderer.create().root; - - children = root.children[0].children; - expect(children[1].props.highlight).to.be.true; - }) - - it('scrolls up to down with select', () => { - let component = ReactTestRenderer.create(); - let instance = component.getInstance(); - let root = component.root; - - let children = root.children[0].children; - expect(children).to.have.lengthOf(3); - expect(children[0].props.title).to.equal('Fruit'); - expect(children[1].props.caption).to.equal('apple'); - expect(children[2].props.caption).to.equal('banana'); - - component.update(); - - children = root.children[0].children; - expect(children).to.have.lengthOf(3); - expect(children[0].props.caption).to.equal('apple'); - expect(children[1].props.caption).to.equal('banana'); - expect(children[2].props.caption).to.equal('cherry'); - expect(children[2].props.highlight).to.be.true; - - component.update(); - - children = root.children[0].children; - expect(children).to.have.lengthOf(3); - expect(children[0].props.caption).to.equal('cherry'); - expect(children[1].props.title).to.equal('Element'); - expect(children[2].props.caption).to.equal('argon'); - expect(children[2].props.highlight).to.be.true; - }); - - it('scrolls down to up with select', () => { - let component = ReactTestRenderer.create(); - let root = component.root; - let instance = component.getInstance(); - - let children = root.children[0].children; - expect(children).to.have.lengthOf(3); - expect(children[0].props.caption).to.equal('argon'); - expect(children[1].props.caption).to.equal('boron'); - expect(children[2].props.caption).to.equal('carbon'); - - component.update(); - - children = root.children[0].children; - expect(children[1].props.highlight).to.be.true; - - component.update(); - - children = root.children[0].children; - expect(children[0].props.highlight).to.be.true; - - component.update(); - - children = root.children[0].children; - expect(children[0].props.caption).to.equal('cherry'); - expect(children[1].props.title).to.equal('Element'); - expect(children[2].props.caption).to.equal('argon'); - expect(children[0].props.highlight).to.be.true; - }); -}); diff --git a/test/console/components/console/Completion.test.tsx b/test/console/components/console/Completion.test.tsx new file mode 100644 index 0000000..16bf11a --- /dev/null +++ b/test/console/components/console/Completion.test.tsx @@ -0,0 +1,168 @@ +import React from 'react'; +import Completion from 'console/components/console/Completion' +import ReactTestRenderer from 'react-test-renderer'; + +describe("console/components/console/completion", () => { + let completions = [{ + name: "Fruit", + items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], + }, { + name: "Element", + items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], + }]; + + it('renders Completion component', () => { + let root = ReactTestRenderer.create().root; + + expect(root.children).to.have.lengthOf(1); + + let children = root.children[0].children; + expect(children).to.have.lengthOf(8); + expect(children[0].props.title).to.equal('Fruit'); + expect(children[1].props.caption).to.equal('apple'); + expect(children[2].props.caption).to.equal('banana'); + expect(children[3].props.caption).to.equal('cherry'); + expect(children[4].props.title).to.equal('Element'); + expect(children[5].props.caption).to.equal('argon'); + expect(children[6].props.caption).to.equal('boron'); + expect(children[7].props.caption).to.equal('carbon'); + }); + + it('highlight current item', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + expect(children[5].props.highlight).to.be.true; + }); + + it('does not highlight any items', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + for (let li of children[0].children) { + expect(li.props.highlight).not.to.be.ok; + } + }); + + it('limits completion items', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + + expect(children[0].props.title).to.equal('Fruit'); + expect(children[1].props.caption).to.equal('apple'); + expect(children[2].props.caption).to.equal('banana'); + + root = ReactTestRenderer.create().root; + + children = root.children[0].children; + expect(children[1].props.highlight).to.be.true; + }) + + it('scrolls up to down with select', () => { + let component = ReactTestRenderer.create(); + let instance = component.getInstance(); + let root = component.root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.title).to.equal('Fruit'); + expect(children[1].props.caption).to.equal('apple'); + expect(children[2].props.caption).to.equal('banana'); + + component.update(); + + children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.caption).to.equal('apple'); + expect(children[1].props.caption).to.equal('banana'); + expect(children[2].props.caption).to.equal('cherry'); + expect(children[2].props.highlight).to.be.true; + + component.update(); + + children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.caption).to.equal('cherry'); + expect(children[1].props.title).to.equal('Element'); + expect(children[2].props.caption).to.equal('argon'); + expect(children[2].props.highlight).to.be.true; + }); + + it('scrolls down to up with select', () => { + let component = ReactTestRenderer.create(); + let root = component.root; + let instance = component.getInstance(); + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.caption).to.equal('argon'); + expect(children[1].props.caption).to.equal('boron'); + expect(children[2].props.caption).to.equal('carbon'); + + component.update(); + + children = root.children[0].children; + expect(children[1].props.highlight).to.be.true; + + component.update(); + + children = root.children[0].children; + expect(children[0].props.highlight).to.be.true; + + component.update(); + + children = root.children[0].children; + expect(children[0].props.caption).to.equal('cherry'); + expect(children[1].props.title).to.equal('Element'); + expect(children[2].props.caption).to.equal('argon'); + expect(children[0].props.highlight).to.be.true; + }); +}); diff --git a/test/console/reducers/console.test.js b/test/console/reducers/console.test.js deleted file mode 100644 index d5a38cf..0000000 --- a/test/console/reducers/console.test.js +++ /dev/null @@ -1,131 +0,0 @@ -import actions from 'console/actions'; -import reducer from 'console/reducers'; - -describe("console reducer", () => { - it('return the initial state', () => { - let state = reducer(undefined, {}); - expect(state).to.have.property('mode', ''); - expect(state).to.have.property('messageText', ''); - expect(state).to.have.property('consoleText', ''); - expect(state).to.have.deep.property('completions', []); - expect(state).to.have.property('select', -1); - }); - - it('return next state for CONSOLE_HIDE', () => { - let action = { type: actions.CONSOLE_HIDE }; - let state = reducer({ mode: 'error' }, action); - expect(state).to.have.property('mode', ''); - }) - - it('return next state for CONSOLE_SHOW_COMMAND', () => { - let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' }; - let state = reducer({}, action); - expect(state).to.have.property('mode', 'command'); - expect(state).to.have.property('consoleText', 'open '); - }); - - it('return next state for CONSOLE_SHOW_INFO', () => { - let action = { type: actions.CONSOLE_SHOW_INFO, text: 'an info' }; - let state = reducer({}, action); - expect(state).to.have.property('mode', 'info'); - expect(state).to.have.property('messageText', 'an info'); - }); - - it('return next state for CONSOLE_SHOW_ERROR', () => { - let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; - let state = reducer({}, action); - expect(state).to.have.property('mode', 'error'); - expect(state).to.have.property('messageText', 'an error'); - }); - - it('return next state for CONSOLE_HIDE_COMMAND', () => { - let action = { type: actions.CONSOLE_HIDE_COMMAND }; - let state = reducer({ mode: 'command' }, action); - expect(state).to.have.property('mode', ''); - - state = reducer({ mode: 'error' }, action); - expect(state).to.have.property('mode', 'error'); - }); - - it('return next state for CONSOLE_SET_CONSOLE_TEXT', () => { - let action = { - type: actions.CONSOLE_SET_CONSOLE_TEXT, - consoleText: 'hello world' - } - let state = reducer({}, action) - - expect(state).to.have.property('consoleText', 'hello world'); - }); - - it ('return next state for CONSOLE_SET_COMPLETIONS', () => { - let state = { - select: 0, - completions: [], - } - let action = { - type: actions.CONSOLE_SET_COMPLETIONS, - completions: [{ - name: 'Apple', - items: [1, 2, 3] - }, { - name: 'Banana', - items: [4, 5, 6] - }] - } - state = reducer(state, action); - expect(state).to.have.property('completions', action.completions); - expect(state).to.have.property('select', -1); - }); - - it ('return next state for CONSOLE_COMPLETION_NEXT', () => { - let action = { type: actions.CONSOLE_COMPLETION_NEXT }; - let state = { - select: -1, - completions: [{ - name: 'Apple', - items: [1, 2] - }, { - name: 'Banana', - items: [3] - }] - }; - - state = reducer(state, action); - expect(state).to.have.property('select', 0); - - state = reducer(state, action); - expect(state).to.have.property('select', 1); - - state = reducer(state, action); - expect(state).to.have.property('select', 2); - - state = reducer(state, action); - expect(state).to.have.property('select', -1); - }); - - it ('return next state for CONSOLE_COMPLETION_PREV', () => { - let action = { type: actions.CONSOLE_COMPLETION_PREV }; - let state = { - select: -1, - completions: [{ - name: 'Apple', - items: [1, 2] - }, { - name: 'Banana', - items: [3] - }] - }; - - state = reducer(state, action); - expect(state).to.have.property('select', 2); - - state = reducer(state, action); - expect(state).to.have.property('select', 1); - - state = reducer(state, action); - expect(state).to.have.property('select', 0); - - state = reducer(state, action); - expect(state).to.have.property('select', -1); - }); -}); diff --git a/test/console/reducers/console.test.ts b/test/console/reducers/console.test.ts new file mode 100644 index 0000000..d5a38cf --- /dev/null +++ b/test/console/reducers/console.test.ts @@ -0,0 +1,131 @@ +import actions from 'console/actions'; +import reducer from 'console/reducers'; + +describe("console reducer", () => { + it('return the initial state', () => { + let state = reducer(undefined, {}); + expect(state).to.have.property('mode', ''); + expect(state).to.have.property('messageText', ''); + expect(state).to.have.property('consoleText', ''); + expect(state).to.have.deep.property('completions', []); + expect(state).to.have.property('select', -1); + }); + + it('return next state for CONSOLE_HIDE', () => { + let action = { type: actions.CONSOLE_HIDE }; + let state = reducer({ mode: 'error' }, action); + expect(state).to.have.property('mode', ''); + }) + + it('return next state for CONSOLE_SHOW_COMMAND', () => { + let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' }; + let state = reducer({}, action); + expect(state).to.have.property('mode', 'command'); + expect(state).to.have.property('consoleText', 'open '); + }); + + it('return next state for CONSOLE_SHOW_INFO', () => { + let action = { type: actions.CONSOLE_SHOW_INFO, text: 'an info' }; + let state = reducer({}, action); + expect(state).to.have.property('mode', 'info'); + expect(state).to.have.property('messageText', 'an info'); + }); + + it('return next state for CONSOLE_SHOW_ERROR', () => { + let action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; + let state = reducer({}, action); + expect(state).to.have.property('mode', 'error'); + expect(state).to.have.property('messageText', 'an error'); + }); + + it('return next state for CONSOLE_HIDE_COMMAND', () => { + let action = { type: actions.CONSOLE_HIDE_COMMAND }; + let state = reducer({ mode: 'command' }, action); + expect(state).to.have.property('mode', ''); + + state = reducer({ mode: 'error' }, action); + expect(state).to.have.property('mode', 'error'); + }); + + it('return next state for CONSOLE_SET_CONSOLE_TEXT', () => { + let action = { + type: actions.CONSOLE_SET_CONSOLE_TEXT, + consoleText: 'hello world' + } + let state = reducer({}, action) + + expect(state).to.have.property('consoleText', 'hello world'); + }); + + it ('return next state for CONSOLE_SET_COMPLETIONS', () => { + let state = { + select: 0, + completions: [], + } + let action = { + type: actions.CONSOLE_SET_COMPLETIONS, + completions: [{ + name: 'Apple', + items: [1, 2, 3] + }, { + name: 'Banana', + items: [4, 5, 6] + }] + } + state = reducer(state, action); + expect(state).to.have.property('completions', action.completions); + expect(state).to.have.property('select', -1); + }); + + it ('return next state for CONSOLE_COMPLETION_NEXT', () => { + let action = { type: actions.CONSOLE_COMPLETION_NEXT }; + let state = { + select: -1, + completions: [{ + name: 'Apple', + items: [1, 2] + }, { + name: 'Banana', + items: [3] + }] + }; + + state = reducer(state, action); + expect(state).to.have.property('select', 0); + + state = reducer(state, action); + expect(state).to.have.property('select', 1); + + state = reducer(state, action); + expect(state).to.have.property('select', 2); + + state = reducer(state, action); + expect(state).to.have.property('select', -1); + }); + + it ('return next state for CONSOLE_COMPLETION_PREV', () => { + let action = { type: actions.CONSOLE_COMPLETION_PREV }; + let state = { + select: -1, + completions: [{ + name: 'Apple', + items: [1, 2] + }, { + name: 'Banana', + items: [3] + }] + }; + + state = reducer(state, action); + expect(state).to.have.property('select', 2); + + state = reducer(state, action); + expect(state).to.have.property('select', 1); + + state = reducer(state, action); + expect(state).to.have.property('select', 0); + + state = reducer(state, action); + expect(state).to.have.property('select', -1); + }); +}); diff --git a/test/content/actions/follow-controller.test.js b/test/content/actions/follow-controller.test.js deleted file mode 100644 index 718a90a..0000000 --- a/test/content/actions/follow-controller.test.js +++ /dev/null @@ -1,34 +0,0 @@ -import actions from 'content/actions'; -import * as followControllerActions from 'content/actions/follow-controller'; - -describe('follow-controller actions', () => { - describe('enable', () => { - it('creates FOLLOW_CONTROLLER_ENABLE action', () => { - let action = followControllerActions.enable(true); - expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_ENABLE); - expect(action.newTab).to.equal(true); - }); - }); - - describe('disable', () => { - it('creates FOLLOW_CONTROLLER_DISABLE action', () => { - let action = followControllerActions.disable(true); - expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_DISABLE); - }); - }); - - describe('keyPress', () => { - it('creates FOLLOW_CONTROLLER_KEY_PRESS action', () => { - let action = followControllerActions.keyPress(100); - expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_KEY_PRESS); - expect(action.key).to.equal(100); - }); - }); - - describe('backspace', () => { - it('creates FOLLOW_CONTROLLER_BACKSPACE action', () => { - let action = followControllerActions.backspace(100); - expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_BACKSPACE); - }); - }); -}); diff --git a/test/content/actions/follow-controller.test.ts b/test/content/actions/follow-controller.test.ts new file mode 100644 index 0000000..718a90a --- /dev/null +++ b/test/content/actions/follow-controller.test.ts @@ -0,0 +1,34 @@ +import actions from 'content/actions'; +import * as followControllerActions from 'content/actions/follow-controller'; + +describe('follow-controller actions', () => { + describe('enable', () => { + it('creates FOLLOW_CONTROLLER_ENABLE action', () => { + let action = followControllerActions.enable(true); + expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_ENABLE); + expect(action.newTab).to.equal(true); + }); + }); + + describe('disable', () => { + it('creates FOLLOW_CONTROLLER_DISABLE action', () => { + let action = followControllerActions.disable(true); + expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_DISABLE); + }); + }); + + describe('keyPress', () => { + it('creates FOLLOW_CONTROLLER_KEY_PRESS action', () => { + let action = followControllerActions.keyPress(100); + expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_KEY_PRESS); + expect(action.key).to.equal(100); + }); + }); + + describe('backspace', () => { + it('creates FOLLOW_CONTROLLER_BACKSPACE action', () => { + let action = followControllerActions.backspace(100); + expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_BACKSPACE); + }); + }); +}); diff --git a/test/content/actions/input.test.js b/test/content/actions/input.test.js deleted file mode 100644 index fe9db5f..0000000 --- a/test/content/actions/input.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import actions from 'content/actions'; -import * as inputActions from 'content/actions/input'; - -describe("input actions", () => { - describe("keyPress", () => { - it('create INPUT_KEY_PRESS action', () => { - let action = inputActions.keyPress('a'); - expect(action.type).to.equal(actions.INPUT_KEY_PRESS); - expect(action.key).to.equal('a'); - }); - }); - - describe("clearKeys", () => { - it('create INPUT_CLEAR_KEYSaction', () => { - let action = inputActions.clearKeys(); - expect(action.type).to.equal(actions.INPUT_CLEAR_KEYS); - }); - }); -}); diff --git a/test/content/actions/input.test.ts b/test/content/actions/input.test.ts new file mode 100644 index 0000000..fe9db5f --- /dev/null +++ b/test/content/actions/input.test.ts @@ -0,0 +1,19 @@ +import actions from 'content/actions'; +import * as inputActions from 'content/actions/input'; + +describe("input actions", () => { + describe("keyPress", () => { + it('create INPUT_KEY_PRESS action', () => { + let action = inputActions.keyPress('a'); + expect(action.type).to.equal(actions.INPUT_KEY_PRESS); + expect(action.key).to.equal('a'); + }); + }); + + describe("clearKeys", () => { + it('create INPUT_CLEAR_KEYSaction', () => { + let action = inputActions.clearKeys(); + expect(action.type).to.equal(actions.INPUT_CLEAR_KEYS); + }); + }); +}); diff --git a/test/content/actions/mark.test.js b/test/content/actions/mark.test.js deleted file mode 100644 index adbf06b..0000000 --- a/test/content/actions/mark.test.js +++ /dev/null @@ -1,35 +0,0 @@ -import actions from 'content/actions'; -import * as markActions from 'content/actions/mark'; - -describe('mark actions', () => { - describe('startSet', () => { - it('create MARK_START_SET action', () => { - let action = markActions.startSet(); - expect(action.type).to.equal(actions.MARK_START_SET); - }); - }); - - describe('startJump', () => { - it('create MARK_START_JUMP action', () => { - let action = markActions.startJump(); - expect(action.type).to.equal(actions.MARK_START_JUMP); - }); - }); - - describe('cancel', () => { - it('create MARK_CANCEL action', () => { - let action = markActions.cancel(); - expect(action.type).to.equal(actions.MARK_CANCEL); - }); - }); - - describe('setLocal', () => { - it('create setLocal action', () => { - let action = markActions.setLocal('a', 20, 30); - expect(action.type).to.equal(actions.MARK_SET_LOCAL); - expect(action.key).to.equal('a'); - expect(action.x).to.equal(20); - expect(action.y).to.equal(30); - }); - }); -}); diff --git a/test/content/actions/mark.test.ts b/test/content/actions/mark.test.ts new file mode 100644 index 0000000..adbf06b --- /dev/null +++ b/test/content/actions/mark.test.ts @@ -0,0 +1,35 @@ +import actions from 'content/actions'; +import * as markActions from 'content/actions/mark'; + +describe('mark actions', () => { + describe('startSet', () => { + it('create MARK_START_SET action', () => { + let action = markActions.startSet(); + expect(action.type).to.equal(actions.MARK_START_SET); + }); + }); + + describe('startJump', () => { + it('create MARK_START_JUMP action', () => { + let action = markActions.startJump(); + expect(action.type).to.equal(actions.MARK_START_JUMP); + }); + }); + + describe('cancel', () => { + it('create MARK_CANCEL action', () => { + let action = markActions.cancel(); + expect(action.type).to.equal(actions.MARK_CANCEL); + }); + }); + + describe('setLocal', () => { + it('create setLocal action', () => { + let action = markActions.setLocal('a', 20, 30); + expect(action.type).to.equal(actions.MARK_SET_LOCAL); + expect(action.key).to.equal('a'); + expect(action.x).to.equal(20); + expect(action.y).to.equal(30); + }); + }); +}); diff --git a/test/content/actions/setting.test.js b/test/content/actions/setting.test.js deleted file mode 100644 index 10f6807..0000000 --- a/test/content/actions/setting.test.js +++ /dev/null @@ -1,35 +0,0 @@ -import actions from 'content/actions'; -import * as settingActions from 'content/actions/setting'; - -describe("setting actions", () => { - describe("set", () => { - it('create SETTING_SET action', () => { - let action = settingActions.set({ red: 'apple', yellow: 'banana' }); - expect(action.type).to.equal(actions.SETTING_SET); - expect(action.value.red).to.equal('apple'); - expect(action.value.yellow).to.equal('banana'); - expect(action.value.keymaps).to.be.empty; - }); - - it('converts keymaps', () => { - let action = settingActions.set({ - keymaps: { - 'dd': 'remove current tab', - 'z': 'increment', - } - }); - let keymaps = action.value.keymaps; - let map = new Map(keymaps); - expect(map).to.have.deep.all.keys( - [ - [{ key: 'Esc', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }], - [{ key: '[', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false }], - [{ key: 'd', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }, - { key: 'd', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }], - [{ key: 'z', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }, - { key: 'a', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false }], - ] - ); - }); - }); -}); diff --git a/test/content/actions/setting.test.ts b/test/content/actions/setting.test.ts new file mode 100644 index 0000000..10f6807 --- /dev/null +++ b/test/content/actions/setting.test.ts @@ -0,0 +1,35 @@ +import actions from 'content/actions'; +import * as settingActions from 'content/actions/setting'; + +describe("setting actions", () => { + describe("set", () => { + it('create SETTING_SET action', () => { + let action = settingActions.set({ red: 'apple', yellow: 'banana' }); + expect(action.type).to.equal(actions.SETTING_SET); + expect(action.value.red).to.equal('apple'); + expect(action.value.yellow).to.equal('banana'); + expect(action.value.keymaps).to.be.empty; + }); + + it('converts keymaps', () => { + let action = settingActions.set({ + keymaps: { + 'dd': 'remove current tab', + 'z': 'increment', + } + }); + let keymaps = action.value.keymaps; + let map = new Map(keymaps); + expect(map).to.have.deep.all.keys( + [ + [{ key: 'Esc', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }], + [{ key: '[', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false }], + [{ key: 'd', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }, + { key: 'd', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }], + [{ key: 'z', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }, + { key: 'a', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false }], + ] + ); + }); + }); +}); diff --git a/test/content/components/common/follow.test.js b/test/content/components/common/follow.test.js deleted file mode 100644 index 90d6cf5..0000000 --- a/test/content/components/common/follow.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import FollowComponent from 'content/components/common/follow'; - -describe('FollowComponent', () => { - describe('#getTargetElements', () => { - beforeEach(() => { - document.body.innerHTML = __html__['test/content/components/common/follow.html']; - }); - - it('returns visible links', () => { - let targets = FollowComponent.getTargetElements( - window, - { width: window.innerWidth, height: window.innerHeight }, - { x: 0, y: 0 }); - expect(targets).to.have.lengthOf(4); - - let ids = Array.prototype.map.call(targets, (e) => e.id); - expect(ids).to.include.members([ - 'visible_a', - 'editable_div_1', - 'editable_div_2', - 'summary_1', - ]); - }); - }); -}); diff --git a/test/content/components/common/follow.test.ts b/test/content/components/common/follow.test.ts new file mode 100644 index 0000000..90d6cf5 --- /dev/null +++ b/test/content/components/common/follow.test.ts @@ -0,0 +1,25 @@ +import FollowComponent from 'content/components/common/follow'; + +describe('FollowComponent', () => { + describe('#getTargetElements', () => { + beforeEach(() => { + document.body.innerHTML = __html__['test/content/components/common/follow.html']; + }); + + it('returns visible links', () => { + let targets = FollowComponent.getTargetElements( + window, + { width: window.innerWidth, height: window.innerHeight }, + { x: 0, y: 0 }); + expect(targets).to.have.lengthOf(4); + + let ids = Array.prototype.map.call(targets, (e) => e.id); + expect(ids).to.include.members([ + 'visible_a', + 'editable_div_1', + 'editable_div_2', + 'summary_1', + ]); + }); + }); +}); diff --git a/test/content/components/common/hint.test.js b/test/content/components/common/hint.test.js deleted file mode 100644 index 42d571f..0000000 --- a/test/content/components/common/hint.test.js +++ /dev/null @@ -1,57 +0,0 @@ -import Hint from 'content/components/common/hint'; - -describe('Hint class', () => { - beforeEach(() => { - document.body.innerHTML = __html__['test/content/components/common/hint.html']; - }); - - describe('#constructor', () => { - it('creates a hint element with tag name', () => { - let link = document.getElementById('test-link'); - let hint = new Hint(link, 'abc'); - expect(hint.element.textContent.trim()).to.be.equal('abc'); - }); - - it('throws an exception when non-element given', () => { - expect(() => new Hint(window, 'abc')).to.throw(TypeError); - }); - }); - - describe('#show', () => { - it('shows an element', () => { - let link = document.getElementById('test-link'); - let hint = new Hint(link, 'abc'); - hint.hide(); - hint.show(); - - expect(hint.element.style.display).to.not.equal('none'); - }); - }); - - describe('#hide', () => { - it('hides an element', () => { - let link = document.getElementById('test-link'); - let hint = new Hint(link, 'abc'); - hint.hide(); - - expect(hint.element.style.display).to.equal('none'); - }); - }); - - describe('#remove', () => { - it('removes an element', () => { - let link = document.getElementById('test-link'); - let hint = new Hint(link, 'abc'); - - expect(hint.element.parentElement).to.not.be.null; - hint.remove(); - expect(hint.element.parentElement).to.be.null; - }); - }); - - describe('#activate', () => { - // TODO test activations - }); -}); - - diff --git a/test/content/components/common/hint.test.ts b/test/content/components/common/hint.test.ts new file mode 100644 index 0000000..42d571f --- /dev/null +++ b/test/content/components/common/hint.test.ts @@ -0,0 +1,57 @@ +import Hint from 'content/components/common/hint'; + +describe('Hint class', () => { + beforeEach(() => { + document.body.innerHTML = __html__['test/content/components/common/hint.html']; + }); + + describe('#constructor', () => { + it('creates a hint element with tag name', () => { + let link = document.getElementById('test-link'); + let hint = new Hint(link, 'abc'); + expect(hint.element.textContent.trim()).to.be.equal('abc'); + }); + + it('throws an exception when non-element given', () => { + expect(() => new Hint(window, 'abc')).to.throw(TypeError); + }); + }); + + describe('#show', () => { + it('shows an element', () => { + let link = document.getElementById('test-link'); + let hint = new Hint(link, 'abc'); + hint.hide(); + hint.show(); + + expect(hint.element.style.display).to.not.equal('none'); + }); + }); + + describe('#hide', () => { + it('hides an element', () => { + let link = document.getElementById('test-link'); + let hint = new Hint(link, 'abc'); + hint.hide(); + + expect(hint.element.style.display).to.equal('none'); + }); + }); + + describe('#remove', () => { + it('removes an element', () => { + let link = document.getElementById('test-link'); + let hint = new Hint(link, 'abc'); + + expect(hint.element.parentElement).to.not.be.null; + hint.remove(); + expect(hint.element.parentElement).to.be.null; + }); + }); + + describe('#activate', () => { + // TODO test activations + }); +}); + + diff --git a/test/content/components/common/input.test.js b/test/content/components/common/input.test.js deleted file mode 100644 index 2ba5507..0000000 --- a/test/content/components/common/input.test.js +++ /dev/null @@ -1,70 +0,0 @@ -import InputComponent from 'content/components/common/input'; - -describe('InputComponent', () => { - it('register callbacks', () => { - let component = new InputComponent(window.document); - let key = { key: 'a', ctrlKey: true, shiftKey: false, altKey: false, metaKey: false }; - component.onKey((key) => { - expect(key).to.deep.equal(key); - }); - component.onKeyDown(key); - }); - - it('invoke callback once', () => { - let component = new InputComponent(window.document); - let a = 0, b = 0; - component.onKey((key) => { - if (key.key == 'a') { - ++a; - } else { - key.key == 'b' - ++b; - } - }); - component.onKeyDown({ key: 'a' }); - component.onKeyDown({ key: 'b' }); - component.onKeyPress({ key: 'a' }); - component.onKeyUp({ key: 'a' }); - component.onKeyPress({ key: 'b' }); - component.onKeyUp({ key: 'b' }); - - expect(a).is.equals(1); - expect(b).is.equals(1); - }) - - it('does not invoke only meta keys', () => { - let component = new InputComponent(window.document); - component.onKey((key) => { - expect.fail(); - }); - component.onKeyDown({ key: 'Shift' }); - component.onKeyDown({ key: 'Control' }); - component.onKeyDown({ key: 'Alt' }); - component.onKeyDown({ key: 'OS' }); - }) - - it('ignores events from input elements', () => { - ['input', 'textarea', 'select'].forEach((name) => { - let target = window.document.createElement(name); - let component = new InputComponent(target); - component.onKey((key) => { - expect.fail(); - }); - component.onKeyDown({ key: 'x', target }); - }); - }); - - it('ignores events from contenteditable elements', () => { - let target = window.document.createElement('div'); - let component = new InputComponent(target); - component.onKey((key) => { - expect.fail(); - }); - - target.setAttribute('contenteditable', ''); - component.onKeyDown({ key: 'x', target }); - - target.setAttribute('contenteditable', 'true'); - component.onKeyDown({ key: 'x', target }); - }) -}); diff --git a/test/content/components/common/input.test.ts b/test/content/components/common/input.test.ts new file mode 100644 index 0000000..2ba5507 --- /dev/null +++ b/test/content/components/common/input.test.ts @@ -0,0 +1,70 @@ +import InputComponent from 'content/components/common/input'; + +describe('InputComponent', () => { + it('register callbacks', () => { + let component = new InputComponent(window.document); + let key = { key: 'a', ctrlKey: true, shiftKey: false, altKey: false, metaKey: false }; + component.onKey((key) => { + expect(key).to.deep.equal(key); + }); + component.onKeyDown(key); + }); + + it('invoke callback once', () => { + let component = new InputComponent(window.document); + let a = 0, b = 0; + component.onKey((key) => { + if (key.key == 'a') { + ++a; + } else { + key.key == 'b' + ++b; + } + }); + component.onKeyDown({ key: 'a' }); + component.onKeyDown({ key: 'b' }); + component.onKeyPress({ key: 'a' }); + component.onKeyUp({ key: 'a' }); + component.onKeyPress({ key: 'b' }); + component.onKeyUp({ key: 'b' }); + + expect(a).is.equals(1); + expect(b).is.equals(1); + }) + + it('does not invoke only meta keys', () => { + let component = new InputComponent(window.document); + component.onKey((key) => { + expect.fail(); + }); + component.onKeyDown({ key: 'Shift' }); + component.onKeyDown({ key: 'Control' }); + component.onKeyDown({ key: 'Alt' }); + component.onKeyDown({ key: 'OS' }); + }) + + it('ignores events from input elements', () => { + ['input', 'textarea', 'select'].forEach((name) => { + let target = window.document.createElement(name); + let component = new InputComponent(target); + component.onKey((key) => { + expect.fail(); + }); + component.onKeyDown({ key: 'x', target }); + }); + }); + + it('ignores events from contenteditable elements', () => { + let target = window.document.createElement('div'); + let component = new InputComponent(target); + component.onKey((key) => { + expect.fail(); + }); + + target.setAttribute('contenteditable', ''); + component.onKeyDown({ key: 'x', target }); + + target.setAttribute('contenteditable', 'true'); + component.onKeyDown({ key: 'x', target }); + }) +}); diff --git a/test/content/hint-key-producer.test.js b/test/content/hint-key-producer.test.js deleted file mode 100644 index dcf477d..0000000 --- a/test/content/hint-key-producer.test.js +++ /dev/null @@ -1,24 +0,0 @@ -import HintKeyProducer from 'content/hint-key-producer'; - -describe('HintKeyProducer class', () => { - describe('#constructor', () => { - it('throws an exception on empty charset', () => { - expect(() => new HintKeyProducer([])).to.throw(TypeError); - }); - }); - - describe('#produce', () => { - it('produce incremented keys', () => { - let charset = 'abc'; - let sequences = [ - 'a', 'b', 'c', - 'aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc', - 'aaa', 'aab', 'aac', 'aba'] - - let producer = new HintKeyProducer(charset); - for (let i = 0; i < sequences.length; ++i) { - expect(producer.produce()).to.equal(sequences[i]); - } - }); - }); -}); diff --git a/test/content/hint-key-producer.test.ts b/test/content/hint-key-producer.test.ts new file mode 100644 index 0000000..dcf477d --- /dev/null +++ b/test/content/hint-key-producer.test.ts @@ -0,0 +1,24 @@ +import HintKeyProducer from 'content/hint-key-producer'; + +describe('HintKeyProducer class', () => { + describe('#constructor', () => { + it('throws an exception on empty charset', () => { + expect(() => new HintKeyProducer([])).to.throw(TypeError); + }); + }); + + describe('#produce', () => { + it('produce incremented keys', () => { + let charset = 'abc'; + let sequences = [ + 'a', 'b', 'c', + 'aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc', + 'aaa', 'aab', 'aac', 'aba'] + + let producer = new HintKeyProducer(charset); + for (let i = 0; i < sequences.length; ++i) { + expect(producer.produce()).to.equal(sequences[i]); + } + }); + }); +}); diff --git a/test/content/navigates.test.js b/test/content/navigates.test.js deleted file mode 100644 index 1d73344..0000000 --- a/test/content/navigates.test.js +++ /dev/null @@ -1,137 +0,0 @@ -import * as navigates from 'content/navigates'; - -const testRel = (done, rel, html) => { - const method = rel === 'prev' ? 'linkPrev' : 'linkNext'; - document.body.innerHTML = html; - navigates[method](window); - setTimeout(() => { - expect(document.location.hash).to.equal(`#${rel}`); - done(); - }, 0); -}; - -const testPrev = html => done => testRel(done, 'prev', html); -const testNext = html => done => testRel(done, 'next', html); - -describe('navigates module', () => { - describe('#linkPrev', () => { - it('navigates to elements whose rel attribute is "prev"', testPrev( - '' - )); - - it('navigates to elements whose rel attribute starts with "prev"', testPrev( - '' - )); - - it('navigates to elements whose rel attribute ends with "prev"', testPrev( - '' - )); - - it('navigates to elements whose rel attribute contains "prev"', testPrev( - '' - )); - - it('navigates to elements whose rel attribute is "prev"', testPrev( - '' - )); - - it('navigates to elements whose rel attribute starts with "prev"', testPrev( - 'click me' - )); - - it('navigates to elements whose rel attribute ends with "prev"', testPrev( - 'click me' - )); - - it('navigates to elements whose rel attribute contains "prev"', testPrev( - 'click me' - )); - - it('navigates to elements whose text matches "prev"', testPrev( - 'previewgo to prev' - )); - - it('navigates to elements whose text matches "previous"', testPrev( - 'previouslyprevious page' - )); - - it('navigates to elements whose decoded text matches "<<"', testPrev( - 'click me<<' - )); - - it('navigates to matching elements by clicking', testPrev( - `` - )); - - it('prefers link[rel~=prev] to a[rel~=prev]', testPrev( - '' - )); - - it('prefers a[rel~=prev] to a::text(pattern)', testPrev( - 'go to prev' - )); - }); - - describe('#linkNext', () => { - it('navigates to elements whose rel attribute is "next"', testNext( - '' - )); - - it('navigates to elements whose rel attribute starts with "next"', testNext( - '' - )); - - it('navigates to elements whose rel attribute ends with "next"', testNext( - '' - )); - - it('navigates to elements whose rel attribute contains "next"', testNext( - '' - )); - - it('navigates to elements whose rel attribute is "next"', testNext( - '' - )); - - it('navigates to elements whose rel attribute starts with "next"', testNext( - 'click me' - )); - - it('navigates to elements whose rel attribute ends with "next"', testNext( - 'click me' - )); - - it('navigates to elements whose rel attribute contains "next"', testNext( - 'click me' - )); - - it('navigates to elements whose text matches "next"', testNext( - 'inextricablego to next' - )); - - it('navigates to elements whose decoded text matches ">>"', testNext( - 'click me>>' - )); - - it('navigates to matching elements by clicking', testNext( - `` - )); - - it('prefers link[rel~=next] to a[rel~=next]', testNext( - '' - )); - - it('prefers a[rel~=next] to a::text(pattern)', testNext( - 'next page' - )); - }); - - describe('#parent', () => { - // NOTE: not able to test location - it('removes hash', () => { - window.location.hash = '#section-1'; - navigates.parent(window); - expect(document.location.hash).to.be.empty; - }); - }); -}); diff --git a/test/content/navigates.test.ts b/test/content/navigates.test.ts new file mode 100644 index 0000000..1d73344 --- /dev/null +++ b/test/content/navigates.test.ts @@ -0,0 +1,137 @@ +import * as navigates from 'content/navigates'; + +const testRel = (done, rel, html) => { + const method = rel === 'prev' ? 'linkPrev' : 'linkNext'; + document.body.innerHTML = html; + navigates[method](window); + setTimeout(() => { + expect(document.location.hash).to.equal(`#${rel}`); + done(); + }, 0); +}; + +const testPrev = html => done => testRel(done, 'prev', html); +const testNext = html => done => testRel(done, 'next', html); + +describe('navigates module', () => { + describe('#linkPrev', () => { + it('navigates to elements whose rel attribute is "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute starts with "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute ends with "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute contains "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute is "prev"', testPrev( + '' + )); + + it('navigates to elements whose rel attribute starts with "prev"', testPrev( + 'click me' + )); + + it('navigates to elements whose rel attribute ends with "prev"', testPrev( + 'click me' + )); + + it('navigates to elements whose rel attribute contains "prev"', testPrev( + 'click me' + )); + + it('navigates to elements whose text matches "prev"', testPrev( + 'previewgo to prev' + )); + + it('navigates to elements whose text matches "previous"', testPrev( + 'previouslyprevious page' + )); + + it('navigates to elements whose decoded text matches "<<"', testPrev( + 'click me<<' + )); + + it('navigates to matching elements by clicking', testPrev( + `` + )); + + it('prefers link[rel~=prev] to a[rel~=prev]', testPrev( + '' + )); + + it('prefers a[rel~=prev] to a::text(pattern)', testPrev( + 'go to prev' + )); + }); + + describe('#linkNext', () => { + it('navigates to elements whose rel attribute is "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute starts with "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute ends with "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute contains "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute is "next"', testNext( + '' + )); + + it('navigates to elements whose rel attribute starts with "next"', testNext( + 'click me' + )); + + it('navigates to elements whose rel attribute ends with "next"', testNext( + 'click me' + )); + + it('navigates to elements whose rel attribute contains "next"', testNext( + 'click me' + )); + + it('navigates to elements whose text matches "next"', testNext( + 'inextricablego to next' + )); + + it('navigates to elements whose decoded text matches ">>"', testNext( + 'click me>>' + )); + + it('navigates to matching elements by clicking', testNext( + `` + )); + + it('prefers link[rel~=next] to a[rel~=next]', testNext( + '' + )); + + it('prefers a[rel~=next] to a::text(pattern)', testNext( + 'next page' + )); + }); + + describe('#parent', () => { + // NOTE: not able to test location + it('removes hash', () => { + window.location.hash = '#section-1'; + navigates.parent(window); + expect(document.location.hash).to.be.empty; + }); + }); +}); diff --git a/test/content/reducers/addon.test.js b/test/content/reducers/addon.test.js deleted file mode 100644 index d4eb845..0000000 --- a/test/content/reducers/addon.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import actions from 'content/actions'; -import addonReducer from 'content/reducers/addon'; - -describe("addon reducer", () => { - it('return the initial state', () => { - let state = addonReducer(undefined, {}); - expect(state).to.have.property('enabled', true); - }); - - it('return next state for ADDON_SET_ENABLED', () => { - let action = { type: actions.ADDON_SET_ENABLED, enabled: true }; - let prev = { enabled: false }; - let state = addonReducer(prev, action); - - expect(state.enabled).is.equal(true); - }); -}); diff --git a/test/content/reducers/addon.test.ts b/test/content/reducers/addon.test.ts new file mode 100644 index 0000000..d4eb845 --- /dev/null +++ b/test/content/reducers/addon.test.ts @@ -0,0 +1,17 @@ +import actions from 'content/actions'; +import addonReducer from 'content/reducers/addon'; + +describe("addon reducer", () => { + it('return the initial state', () => { + let state = addonReducer(undefined, {}); + expect(state).to.have.property('enabled', true); + }); + + it('return next state for ADDON_SET_ENABLED', () => { + let action = { type: actions.ADDON_SET_ENABLED, enabled: true }; + let prev = { enabled: false }; + let state = addonReducer(prev, action); + + expect(state.enabled).is.equal(true); + }); +}); diff --git a/test/content/reducers/find.test.js b/test/content/reducers/find.test.js deleted file mode 100644 index a8c30d7..0000000 --- a/test/content/reducers/find.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import actions from 'content/actions'; -import findReducer from 'content/reducers/find'; - -describe("find reducer", () => { - it('return the initial state', () => { - let state = findReducer(undefined, {}); - expect(state).to.have.property('keyword', null); - expect(state).to.have.property('found', false); - }); - - it('return next state for FIND_SET_KEYWORD', () => { - let action = { - type: actions.FIND_SET_KEYWORD, - keyword: 'xyz', - found: true, - }; - let state = findReducer({}, action); - - expect(state.keyword).is.equal('xyz'); - expect(state.found).to.be.true; - }); -}); diff --git a/test/content/reducers/find.test.ts b/test/content/reducers/find.test.ts new file mode 100644 index 0000000..a8c30d7 --- /dev/null +++ b/test/content/reducers/find.test.ts @@ -0,0 +1,22 @@ +import actions from 'content/actions'; +import findReducer from 'content/reducers/find'; + +describe("find reducer", () => { + it('return the initial state', () => { + let state = findReducer(undefined, {}); + expect(state).to.have.property('keyword', null); + expect(state).to.have.property('found', false); + }); + + it('return next state for FIND_SET_KEYWORD', () => { + let action = { + type: actions.FIND_SET_KEYWORD, + keyword: 'xyz', + found: true, + }; + let state = findReducer({}, action); + + expect(state.keyword).is.equal('xyz'); + expect(state.found).to.be.true; + }); +}); diff --git a/test/content/reducers/follow-controller.test.js b/test/content/reducers/follow-controller.test.js deleted file mode 100644 index 8a4c2d4..0000000 --- a/test/content/reducers/follow-controller.test.js +++ /dev/null @@ -1,47 +0,0 @@ -import actions from 'content/actions'; -import followControllerReducer from 'content/reducers/follow-controller'; - -describe('follow-controller reducer', () => { - it ('returns the initial state', () => { - let state = followControllerReducer(undefined, {}); - expect(state).to.have.property('enabled', false); - expect(state).to.have.property('newTab'); - expect(state).to.have.deep.property('keys', ''); - }); - - it ('returns next state for FOLLOW_CONTROLLER_ENABLE', () => { - let action = { type: actions.FOLLOW_CONTROLLER_ENABLE, newTab: true }; - let state = followControllerReducer({ enabled: false, newTab: false }, action); - expect(state).to.have.property('enabled', true); - expect(state).to.have.property('newTab', true); - expect(state).to.have.property('keys', ''); - }); - - it ('returns next state for FOLLOW_CONTROLLER_DISABLE', () => { - let action = { type: actions.FOLLOW_CONTROLLER_DISABLE }; - let state = followControllerReducer({ enabled: true }, action); - expect(state).to.have.property('enabled', false); - }); - - it ('returns next state for FOLLOW_CONTROLLER_KEY_PRESS', () => { - let action = { type: actions.FOLLOW_CONTROLLER_KEY_PRESS, key: 'a'}; - let state = followControllerReducer({ keys: '' }, action); - expect(state).to.have.deep.property('keys', 'a'); - - action = { type: actions.FOLLOW_CONTROLLER_KEY_PRESS, key: 'b'}; - state = followControllerReducer(state, action); - expect(state).to.have.deep.property('keys', 'ab'); - }); - - it ('returns next state for FOLLOW_CONTROLLER_BACKSPACE', () => { - let action = { type: actions.FOLLOW_CONTROLLER_BACKSPACE }; - let state = followControllerReducer({ keys: 'ab' }, action); - expect(state).to.have.deep.property('keys', 'a'); - - state = followControllerReducer(state, action); - expect(state).to.have.deep.property('keys', ''); - - state = followControllerReducer(state, action); - expect(state).to.have.deep.property('keys', ''); - }); -}); diff --git a/test/content/reducers/follow-controller.test.ts b/test/content/reducers/follow-controller.test.ts new file mode 100644 index 0000000..8a4c2d4 --- /dev/null +++ b/test/content/reducers/follow-controller.test.ts @@ -0,0 +1,47 @@ +import actions from 'content/actions'; +import followControllerReducer from 'content/reducers/follow-controller'; + +describe('follow-controller reducer', () => { + it ('returns the initial state', () => { + let state = followControllerReducer(undefined, {}); + expect(state).to.have.property('enabled', false); + expect(state).to.have.property('newTab'); + expect(state).to.have.deep.property('keys', ''); + }); + + it ('returns next state for FOLLOW_CONTROLLER_ENABLE', () => { + let action = { type: actions.FOLLOW_CONTROLLER_ENABLE, newTab: true }; + let state = followControllerReducer({ enabled: false, newTab: false }, action); + expect(state).to.have.property('enabled', true); + expect(state).to.have.property('newTab', true); + expect(state).to.have.property('keys', ''); + }); + + it ('returns next state for FOLLOW_CONTROLLER_DISABLE', () => { + let action = { type: actions.FOLLOW_CONTROLLER_DISABLE }; + let state = followControllerReducer({ enabled: true }, action); + expect(state).to.have.property('enabled', false); + }); + + it ('returns next state for FOLLOW_CONTROLLER_KEY_PRESS', () => { + let action = { type: actions.FOLLOW_CONTROLLER_KEY_PRESS, key: 'a'}; + let state = followControllerReducer({ keys: '' }, action); + expect(state).to.have.deep.property('keys', 'a'); + + action = { type: actions.FOLLOW_CONTROLLER_KEY_PRESS, key: 'b'}; + state = followControllerReducer(state, action); + expect(state).to.have.deep.property('keys', 'ab'); + }); + + it ('returns next state for FOLLOW_CONTROLLER_BACKSPACE', () => { + let action = { type: actions.FOLLOW_CONTROLLER_BACKSPACE }; + let state = followControllerReducer({ keys: 'ab' }, action); + expect(state).to.have.deep.property('keys', 'a'); + + state = followControllerReducer(state, action); + expect(state).to.have.deep.property('keys', ''); + + state = followControllerReducer(state, action); + expect(state).to.have.deep.property('keys', ''); + }); +}); diff --git a/test/content/reducers/input.test.js b/test/content/reducers/input.test.js deleted file mode 100644 index 0011943..0000000 --- a/test/content/reducers/input.test.js +++ /dev/null @@ -1,25 +0,0 @@ -import actions from 'content/actions'; -import inputReducer from 'content/reducers/input'; - -describe("input reducer", () => { - it('return the initial state', () => { - let state = inputReducer(undefined, {}); - expect(state).to.have.deep.property('keys', []); - }); - - it('return next state for INPUT_KEY_PRESS', () => { - let action = { type: actions.INPUT_KEY_PRESS, key: 'a' }; - let state = inputReducer(undefined, action); - expect(state).to.have.deep.property('keys', ['a']); - - action = { type: actions.INPUT_KEY_PRESS, key: 'b' }; - state = inputReducer(state, action); - expect(state).to.have.deep.property('keys', ['a', 'b']); - }); - - it('return next state for INPUT_CLEAR_KEYS', () => { - let action = { type: actions.INPUT_CLEAR_KEYS }; - let state = inputReducer({ keys: [1, 2, 3] }, action); - expect(state).to.have.deep.property('keys', []); - }); -}); diff --git a/test/content/reducers/input.test.ts b/test/content/reducers/input.test.ts new file mode 100644 index 0000000..0011943 --- /dev/null +++ b/test/content/reducers/input.test.ts @@ -0,0 +1,25 @@ +import actions from 'content/actions'; +import inputReducer from 'content/reducers/input'; + +describe("input reducer", () => { + it('return the initial state', () => { + let state = inputReducer(undefined, {}); + expect(state).to.have.deep.property('keys', []); + }); + + it('return next state for INPUT_KEY_PRESS', () => { + let action = { type: actions.INPUT_KEY_PRESS, key: 'a' }; + let state = inputReducer(undefined, action); + expect(state).to.have.deep.property('keys', ['a']); + + action = { type: actions.INPUT_KEY_PRESS, key: 'b' }; + state = inputReducer(state, action); + expect(state).to.have.deep.property('keys', ['a', 'b']); + }); + + it('return next state for INPUT_CLEAR_KEYS', () => { + let action = { type: actions.INPUT_CLEAR_KEYS }; + let state = inputReducer({ keys: [1, 2, 3] }, action); + expect(state).to.have.deep.property('keys', []); + }); +}); diff --git a/test/content/reducers/mark.test.js b/test/content/reducers/mark.test.js deleted file mode 100644 index 76efbf7..0000000 --- a/test/content/reducers/mark.test.js +++ /dev/null @@ -1,41 +0,0 @@ -import actions from 'content/actions'; -import reducer from 'content/reducers/mark'; - -describe("mark reducer", () => { - it('return the initial state', () => { - let state = reducer(undefined, {}); - expect(state.setMode).to.be.false; - expect(state.jumpMode).to.be.false; - expect(state.marks).to.be.empty; - }); - - it('starts set mode', () => { - let action = { type: actions.MARK_START_SET }; - let state = reducer(undefined, action); - expect(state.setMode).to.be.true; - }); - - it('starts jump mode', () => { - let action = { type: actions.MARK_START_JUMP }; - let state = reducer(undefined, action); - expect(state.jumpMode).to.be.true; - }); - - it('cancels set and jump mode', () => { - let action = { type: actions.MARK_CANCEL }; - let state = reducer({ setMode: true }, action); - expect(state.setMode).to.be.false; - - state = reducer({ jumpMode: true }, action); - expect(state.jumpMode).to.be.false; - }); - - it('stores local mark', () => { - let action = { type: actions.MARK_SET_LOCAL, key: 'a', x: 20, y: 30}; - let state = reducer({ setMode: true }, action); - expect(state.setMode).to.be.false; - expect(state.marks['a']).to.be.an('object') - expect(state.marks['a'].x).to.equal(20) - expect(state.marks['a'].y).to.equal(30) - }); -}); diff --git a/test/content/reducers/mark.test.ts b/test/content/reducers/mark.test.ts new file mode 100644 index 0000000..76efbf7 --- /dev/null +++ b/test/content/reducers/mark.test.ts @@ -0,0 +1,41 @@ +import actions from 'content/actions'; +import reducer from 'content/reducers/mark'; + +describe("mark reducer", () => { + it('return the initial state', () => { + let state = reducer(undefined, {}); + expect(state.setMode).to.be.false; + expect(state.jumpMode).to.be.false; + expect(state.marks).to.be.empty; + }); + + it('starts set mode', () => { + let action = { type: actions.MARK_START_SET }; + let state = reducer(undefined, action); + expect(state.setMode).to.be.true; + }); + + it('starts jump mode', () => { + let action = { type: actions.MARK_START_JUMP }; + let state = reducer(undefined, action); + expect(state.jumpMode).to.be.true; + }); + + it('cancels set and jump mode', () => { + let action = { type: actions.MARK_CANCEL }; + let state = reducer({ setMode: true }, action); + expect(state.setMode).to.be.false; + + state = reducer({ jumpMode: true }, action); + expect(state.jumpMode).to.be.false; + }); + + it('stores local mark', () => { + let action = { type: actions.MARK_SET_LOCAL, key: 'a', x: 20, y: 30}; + let state = reducer({ setMode: true }, action); + expect(state.setMode).to.be.false; + expect(state.marks['a']).to.be.an('object') + expect(state.marks['a'].x).to.equal(20) + expect(state.marks['a'].y).to.equal(30) + }); +}); diff --git a/test/content/reducers/setting.test.js b/test/content/reducers/setting.test.js deleted file mode 100644 index 4e4c095..0000000 --- a/test/content/reducers/setting.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import actions from 'content/actions'; -import settingReducer from 'content/reducers/setting'; - -describe("content setting reducer", () => { - it('return the initial state', () => { - let state = settingReducer(undefined, {}); - expect(state.keymaps).to.be.empty; - }); - - it('return next state for SETTING_SET', () => { - let newSettings = { red: 'apple', yellow: 'banana' }; - let action = { type: actions.SETTING_SET, value: newSettings }; - let state = settingReducer(undefined, action); - expect(state).to.deep.equal(newSettings); - expect(state).not.to.equal(newSettings); // assert deep copy - }); -}); diff --git a/test/content/reducers/setting.test.ts b/test/content/reducers/setting.test.ts new file mode 100644 index 0000000..4e4c095 --- /dev/null +++ b/test/content/reducers/setting.test.ts @@ -0,0 +1,17 @@ +import actions from 'content/actions'; +import settingReducer from 'content/reducers/setting'; + +describe("content setting reducer", () => { + it('return the initial state', () => { + let state = settingReducer(undefined, {}); + expect(state.keymaps).to.be.empty; + }); + + it('return next state for SETTING_SET', () => { + let newSettings = { red: 'apple', yellow: 'banana' }; + let action = { type: actions.SETTING_SET, value: newSettings }; + let state = settingReducer(undefined, action); + expect(state).to.deep.equal(newSettings); + expect(state).not.to.equal(newSettings); // assert deep copy + }); +}); diff --git a/test/main.js b/test/main.js deleted file mode 100644 index 3aeae69..0000000 --- a/test/main.js +++ /dev/null @@ -1,6 +0,0 @@ -import chai from 'chai'; -const browserFake = require('webextensions-api-fake'); -const browser = browserFake(); - -global.expect = chai.expect; -global.browser = browser; diff --git a/test/main.ts b/test/main.ts new file mode 100644 index 0000000..3aeae69 --- /dev/null +++ b/test/main.ts @@ -0,0 +1,6 @@ +import chai from 'chai'; +const browserFake = require('webextensions-api-fake'); +const browser = browserFake(); + +global.expect = chai.expect; +global.browser = browser; diff --git a/test/settings/components/form/BlacklistForm.test.jsx b/test/settings/components/form/BlacklistForm.test.jsx deleted file mode 100644 index 2be5d96..0000000 --- a/test/settings/components/form/BlacklistForm.test.jsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import BlacklistForm from 'settings/components/form/BlacklistForm' - -describe("settings/form/BlacklistForm", () => { - describe('render', () => { - it('renders BlacklistForm', () => { - let root = ReactTestRenderer.create( - , - ).root; - - let children = root.children[0].children; - expect(children).to.have.lengthOf(3); - expect(children[0].children[0].props.value).to.equal('*.slack.com'); - expect(children[1].children[0].props.value).to.equal('www.google.com/maps'); - expect(children[2].props.name).to.equal('add'); - }); - - it('renders blank value', () => { - let root = ReactTestRenderer.create().root; - - let children = root.children[0].children; - expect(children).to.have.lengthOf(1); - expect(children[0].props.name).to.equal('add'); - }); - }); - - describe('onChange', () => { - let container; - - beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - afterEach(() => { - document.body.removeChild(container); - container = null; - }); - - it('invokes onChange event on edit', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value).to.have.lengthOf(2); - expect(value).to.have.members(['gitter.im', 'www.google.com/maps*']); - done(); - }} - />, container) - }); - - let input = document.querySelectorAll('input[type=text]')[0]; - input.value = 'gitter.im'; - ReactTestUtils.Simulate.change(input); - }); - - it('invokes onChange event on delete', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value).to.have.lengthOf(1); - expect(value).to.have.members(['www.google.com/maps*']); - done(); - }} - />, container) - }); - - let button = document.querySelectorAll('input[type=button]')[0]; - ReactTestUtils.Simulate.click(button); - }); - - it('invokes onChange event on add', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value).to.have.lengthOf(2); - expect(value).to.have.members(['*.slack.com', '']); - done(); - }} - />, container); - }); - - let button = document.querySelector('input[type=button].ui-add-button'); - ReactTestUtils.Simulate.click(button); - }); - }); -}); diff --git a/test/settings/components/form/BlacklistForm.test.tsx b/test/settings/components/form/BlacklistForm.test.tsx new file mode 100644 index 0000000..2be5d96 --- /dev/null +++ b/test/settings/components/form/BlacklistForm.test.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import BlacklistForm from 'settings/components/form/BlacklistForm' + +describe("settings/form/BlacklistForm", () => { + describe('render', () => { + it('renders BlacklistForm', () => { + let root = ReactTestRenderer.create( + , + ).root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].children[0].props.value).to.equal('*.slack.com'); + expect(children[1].children[0].props.value).to.equal('www.google.com/maps'); + expect(children[2].props.name).to.equal('add'); + }); + + it('renders blank value', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(1); + expect(children[0].props.name).to.equal('add'); + }); + }); + + describe('onChange', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on edit', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.lengthOf(2); + expect(value).to.have.members(['gitter.im', 'www.google.com/maps*']); + done(); + }} + />, container) + }); + + let input = document.querySelectorAll('input[type=text]')[0]; + input.value = 'gitter.im'; + ReactTestUtils.Simulate.change(input); + }); + + it('invokes onChange event on delete', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.lengthOf(1); + expect(value).to.have.members(['www.google.com/maps*']); + done(); + }} + />, container) + }); + + let button = document.querySelectorAll('input[type=button]')[0]; + ReactTestUtils.Simulate.click(button); + }); + + it('invokes onChange event on add', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.lengthOf(2); + expect(value).to.have.members(['*.slack.com', '']); + done(); + }} + />, container); + }); + + let button = document.querySelector('input[type=button].ui-add-button'); + ReactTestUtils.Simulate.click(button); + }); + }); +}); diff --git a/test/settings/components/form/KeymapsForm.test.jsx b/test/settings/components/form/KeymapsForm.test.jsx deleted file mode 100644 index 6ac57c9..0000000 --- a/test/settings/components/form/KeymapsForm.test.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import KeymapsForm from 'settings/components/form/KeymapsForm' - -describe("settings/form/KeymapsForm", () => { - describe('render', () => { - it('renders keymap fields', () => { - let root = ReactTestRenderer.create().root - - let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); - let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); - - expect(inputj.props.value).to.equal('j'); - expect(inputk.props.value).to.equal('k'); - }); - - it('renders blank value', () => { - let root = ReactTestRenderer.create().root; - - let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); - let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); - - expect(inputj.props.value).to.be.empty; - expect(inputk.props.value).to.be.empty; - }); - }); - - describe('onChange event', () => { - let container; - - beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - afterEach(() => { - document.body.removeChild(container); - container = null; - }); - - it('invokes onChange event on edit', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value['scroll.vertically?{"count":1}']).to.equal('jjj'); - done(); - }} />, container); - }); - - let input = document.getElementById('scroll.vertically?{"count":1}'); - input.value = 'jjj'; - ReactTestUtils.Simulate.change(input); - }); - }); -}); diff --git a/test/settings/components/form/KeymapsForm.test.tsx b/test/settings/components/form/KeymapsForm.test.tsx new file mode 100644 index 0000000..6ac57c9 --- /dev/null +++ b/test/settings/components/form/KeymapsForm.test.tsx @@ -0,0 +1,64 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import KeymapsForm from 'settings/components/form/KeymapsForm' + +describe("settings/form/KeymapsForm", () => { + describe('render', () => { + it('renders keymap fields', () => { + let root = ReactTestRenderer.create().root + + let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); + let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); + + expect(inputj.props.value).to.equal('j'); + expect(inputk.props.value).to.equal('k'); + }); + + it('renders blank value', () => { + let root = ReactTestRenderer.create().root; + + let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); + let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); + + expect(inputj.props.value).to.be.empty; + expect(inputk.props.value).to.be.empty; + }); + }); + + describe('onChange event', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on edit', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value['scroll.vertically?{"count":1}']).to.equal('jjj'); + done(); + }} />, container); + }); + + let input = document.getElementById('scroll.vertically?{"count":1}'); + input.value = 'jjj'; + ReactTestUtils.Simulate.change(input); + }); + }); +}); diff --git a/test/settings/components/form/PropertiesForm.test.jsx b/test/settings/components/form/PropertiesForm.test.jsx deleted file mode 100644 index 80f60d2..0000000 --- a/test/settings/components/form/PropertiesForm.test.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import PropertiesForm from 'settings/components/form/PropertiesForm' - -describe("settings/form/PropertiesForm", () => { - describe('render', () => { - it('renders PropertiesForm', () => { - let types = { - mystr: 'string', - mynum: 'number', - mybool: 'boolean', - empty: 'string', - } - let value = { - mystr: 'abc', - mynum: 123, - mybool: true, - }; - - let root = ReactTestRenderer.create( - , - ).root - - let input = root.findByProps({ name: 'mystr' }); - expect(input.props.type).to.equals('text'); - expect(input.props.value).to.equal('abc'); - - input = root.findByProps({ name: 'mynum' }); - expect(input.props.type).to.equals('number'); - expect(input.props.value).to.equal(123); - - input = root.findByProps({ name: 'mybool' }); - expect(input.props.type).to.equals('checkbox'); - expect(input.props.value).to.equal(true); - }); - }); - - describe('onChange', () => { - let container; - - beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - afterEach(() => { - document.body.removeChild(container); - container = null; - }); - - it('invokes onChange event on text changed', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value).to.have.property('myvalue', 'abcd'); - done(); - }} - />, container); - }); - - let input = document.querySelector('input[name=myvalue]'); - input.value = 'abcd' - ReactTestUtils.Simulate.change(input); - }); - - it('invokes onChange event on number changeed', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value).to.have.property('myvalue', 1234); - done(); - }} - />, container); - }); - - let input = document.querySelector('input[name=myvalue]'); - input.value = '1234' - ReactTestUtils.Simulate.change(input); - }); - - it('invokes onChange event on checkbox changed', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value).to.have.property('myvalue', true); - done(); - }} - />, container); - }); - - let input = document.querySelector('input[name=myvalue]'); - input.checked = true; - ReactTestUtils.Simulate.change(input); - }); - }); -}); diff --git a/test/settings/components/form/PropertiesForm.test.tsx b/test/settings/components/form/PropertiesForm.test.tsx new file mode 100644 index 0000000..80f60d2 --- /dev/null +++ b/test/settings/components/form/PropertiesForm.test.tsx @@ -0,0 +1,104 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import PropertiesForm from 'settings/components/form/PropertiesForm' + +describe("settings/form/PropertiesForm", () => { + describe('render', () => { + it('renders PropertiesForm', () => { + let types = { + mystr: 'string', + mynum: 'number', + mybool: 'boolean', + empty: 'string', + } + let value = { + mystr: 'abc', + mynum: 123, + mybool: true, + }; + + let root = ReactTestRenderer.create( + , + ).root + + let input = root.findByProps({ name: 'mystr' }); + expect(input.props.type).to.equals('text'); + expect(input.props.value).to.equal('abc'); + + input = root.findByProps({ name: 'mynum' }); + expect(input.props.type).to.equals('number'); + expect(input.props.value).to.equal(123); + + input = root.findByProps({ name: 'mybool' }); + expect(input.props.type).to.equals('checkbox'); + expect(input.props.value).to.equal(true); + }); + }); + + describe('onChange', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on text changed', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.property('myvalue', 'abcd'); + done(); + }} + />, container); + }); + + let input = document.querySelector('input[name=myvalue]'); + input.value = 'abcd' + ReactTestUtils.Simulate.change(input); + }); + + it('invokes onChange event on number changeed', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.property('myvalue', 1234); + done(); + }} + />, container); + }); + + let input = document.querySelector('input[name=myvalue]'); + input.value = '1234' + ReactTestUtils.Simulate.change(input); + }); + + it('invokes onChange event on checkbox changed', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.property('myvalue', true); + done(); + }} + />, container); + }); + + let input = document.querySelector('input[name=myvalue]'); + input.checked = true; + ReactTestUtils.Simulate.change(input); + }); + }); +}); diff --git a/test/settings/components/form/SearchEngineForm.test.jsx b/test/settings/components/form/SearchEngineForm.test.jsx deleted file mode 100644 index 06822f2..0000000 --- a/test/settings/components/form/SearchEngineForm.test.jsx +++ /dev/null @@ -1,128 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import SearchForm from 'settings/components/form/SearchForm' - -describe("settings/form/SearchForm", () => { - describe('render', () => { - it('renders SearchForm', () => { - let root = ReactTestRenderer.create().root; - - let names = root.findAllByProps({ name: 'name' }); - expect(names).to.have.lengthOf(2); - expect(names[0].props.value).to.equal('google'); - expect(names[1].props.value).to.equal('yahoo'); - - let urls = root.findAllByProps({ name: 'url' }); - expect(urls).to.have.lengthOf(2); - expect(urls[0].props.value).to.equal('google.com'); - expect(urls[1].props.value).to.equal('yahoo.com'); - }); - - it('renders blank value', () => { - let root = ReactTestRenderer.create().root; - - let names = root.findAllByProps({ name: 'name' }); - expect(names).to.be.empty; - - let urls = root.findAllByProps({ name: 'url' }); - expect(urls).to.be.empty; - }); - - it('renders blank engines', () => { - let root = ReactTestRenderer.create( - , - ).root; - - let names = root.findAllByProps({ name: 'name' }); - expect(names).to.be.empty; - - let urls = root.findAllByProps({ name: 'url' }); - expect(urls).to.be.empty; - }); - }); - - describe('onChange event', () => { - let container; - - beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - afterEach(() => { - document.body.removeChild(container); - container = null; - }); - - it('invokes onChange event on edit', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value.default).to.equal('louvre'); - expect(value.engines).to.have.lengthOf(2) - expect(value.engines).to.have.deep.members( - [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] - ); - done(); - }} />, container); - }); - - let radio = document.querySelectorAll('input[type=radio]'); - radio.checked = true; - - let name = document.querySelector('input[name=name]'); - name.value = 'louvre'; - - ReactTestUtils.Simulate.change(name); - }); - - it('invokes onChange event on delete', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value.default).to.equal('yahoo'); - expect(value.engines).to.have.lengthOf(1) - expect(value.engines).to.have.deep.members( - [['yahoo', 'yahoo.com']] - ); - done(); - }} />, container); - }); - - let button = document.querySelector('input[type=button]'); - ReactTestUtils.Simulate.click(button); - }); - - it('invokes onChange event on add', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(value.default).to.equal('yahoo'); - expect(value.engines).to.have.lengthOf(2) - expect(value.engines).to.have.deep.members( - [['google', 'google.com'], ['', '']], - ); - done(); - }} />, container); - }); - - let button = document.querySelector('input[type=button].ui-add-button'); - ReactTestUtils.Simulate.click(button); - }); - }); -}); diff --git a/test/settings/components/form/SearchEngineForm.test.tsx b/test/settings/components/form/SearchEngineForm.test.tsx new file mode 100644 index 0000000..06822f2 --- /dev/null +++ b/test/settings/components/form/SearchEngineForm.test.tsx @@ -0,0 +1,128 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import SearchForm from 'settings/components/form/SearchForm' + +describe("settings/form/SearchForm", () => { + describe('render', () => { + it('renders SearchForm', () => { + let root = ReactTestRenderer.create().root; + + let names = root.findAllByProps({ name: 'name' }); + expect(names).to.have.lengthOf(2); + expect(names[0].props.value).to.equal('google'); + expect(names[1].props.value).to.equal('yahoo'); + + let urls = root.findAllByProps({ name: 'url' }); + expect(urls).to.have.lengthOf(2); + expect(urls[0].props.value).to.equal('google.com'); + expect(urls[1].props.value).to.equal('yahoo.com'); + }); + + it('renders blank value', () => { + let root = ReactTestRenderer.create().root; + + let names = root.findAllByProps({ name: 'name' }); + expect(names).to.be.empty; + + let urls = root.findAllByProps({ name: 'url' }); + expect(urls).to.be.empty; + }); + + it('renders blank engines', () => { + let root = ReactTestRenderer.create( + , + ).root; + + let names = root.findAllByProps({ name: 'name' }); + expect(names).to.be.empty; + + let urls = root.findAllByProps({ name: 'url' }); + expect(urls).to.be.empty; + }); + }); + + describe('onChange event', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on edit', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value.default).to.equal('louvre'); + expect(value.engines).to.have.lengthOf(2) + expect(value.engines).to.have.deep.members( + [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] + ); + done(); + }} />, container); + }); + + let radio = document.querySelectorAll('input[type=radio]'); + radio.checked = true; + + let name = document.querySelector('input[name=name]'); + name.value = 'louvre'; + + ReactTestUtils.Simulate.change(name); + }); + + it('invokes onChange event on delete', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value.default).to.equal('yahoo'); + expect(value.engines).to.have.lengthOf(1) + expect(value.engines).to.have.deep.members( + [['yahoo', 'yahoo.com']] + ); + done(); + }} />, container); + }); + + let button = document.querySelector('input[type=button]'); + ReactTestUtils.Simulate.click(button); + }); + + it('invokes onChange event on add', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value.default).to.equal('yahoo'); + expect(value.engines).to.have.lengthOf(2) + expect(value.engines).to.have.deep.members( + [['google', 'google.com'], ['', '']], + ); + done(); + }} />, container); + }); + + let button = document.querySelector('input[type=button].ui-add-button'); + ReactTestUtils.Simulate.click(button); + }); + }); +}); diff --git a/test/settings/components/ui/input.test.jsx b/test/settings/components/ui/input.test.jsx deleted file mode 100644 index 432efcb..0000000 --- a/test/settings/components/ui/input.test.jsx +++ /dev/null @@ -1,111 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestUtils from 'react-dom/test-utils'; -import Input from 'settings/components/ui/Input' - -describe("settings/ui/Input", () => { - let container; - - beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - }); - - afterEach(() => { - document.body.removeChild(container); - container = null; - }); - - context("type=text", () => { - it('renders text input', () => { - ReactTestUtils.act(() => { - ReactDOM.render( - , - container); - }); - - let label = document.querySelector('label'); - let input = document.querySelector('input'); - expect(label.textContent).to.contain('myfield'); - expect(input.type).to.contain('text'); - expect(input.name).to.contain('myname'); - expect(input.value).to.contain('myvalue'); - }); - - it('invoke onChange', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(e.target.value).to.equal('newvalue'); - done(); - }}/>, container); - }); - - let input = document.querySelector('input'); - input.value = 'newvalue'; - ReactTestUtils.Simulate.change(input); - }); - }); - - context("type=radio", () => { - it('renders radio button', () => { - ReactTestUtils.act(() => { - ReactDOM.render( - , - container); - }); - - let label = document.querySelector('label'); - let input = document.querySelector('input'); - expect(label.textContent).to.contain('myfield'); - expect(input.type).to.contain('radio'); - expect(input.name).to.contain('myname'); - expect(input.value).to.contain('myvalue'); - }); - - it('invoke onChange', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(e.target.checked).to.be.true; - done(); - }}/>, - container); - }); - - let input = document.querySelector('input'); - input.checked = true; - ReactTestUtils.Simulate.change(input); - }); - }); - - context("type=textarea", () => { - it('renders textarea button', () => { - ReactTestUtils.act(() => { - ReactDOM.render( - , - container); - }); - - let label = document.querySelector('label'); - let textarea = document.querySelector('textarea'); - let error = document.querySelector('.settings-ui-input-error'); - expect(label.textContent).to.contain('myfield'); - expect(textarea.nodeName).to.contain('TEXTAREA'); - expect(textarea.name).to.contain('myname'); - expect(textarea.value).to.contain('myvalue'); - expect(error.textContent).to.contain('myerror'); - }); - - it('invoke onChange', (done) => { - ReactTestUtils.act(() => { - ReactDOM.render( { - expect(e.target.value).to.equal('newvalue'); - done(); - }}/>, container); - }); - - let input = document.querySelector('textarea'); - input.value = 'newvalue' - ReactTestUtils.Simulate.change(input); - }); - }); -}); diff --git a/test/settings/components/ui/input.test.tsx b/test/settings/components/ui/input.test.tsx new file mode 100644 index 0000000..432efcb --- /dev/null +++ b/test/settings/components/ui/input.test.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestUtils from 'react-dom/test-utils'; +import Input from 'settings/components/ui/Input' + +describe("settings/ui/Input", () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + context("type=text", () => { + it('renders text input', () => { + ReactTestUtils.act(() => { + ReactDOM.render( + , + container); + }); + + let label = document.querySelector('label'); + let input = document.querySelector('input'); + expect(label.textContent).to.contain('myfield'); + expect(input.type).to.contain('text'); + expect(input.name).to.contain('myname'); + expect(input.value).to.contain('myvalue'); + }); + + it('invoke onChange', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(e.target.value).to.equal('newvalue'); + done(); + }}/>, container); + }); + + let input = document.querySelector('input'); + input.value = 'newvalue'; + ReactTestUtils.Simulate.change(input); + }); + }); + + context("type=radio", () => { + it('renders radio button', () => { + ReactTestUtils.act(() => { + ReactDOM.render( + , + container); + }); + + let label = document.querySelector('label'); + let input = document.querySelector('input'); + expect(label.textContent).to.contain('myfield'); + expect(input.type).to.contain('radio'); + expect(input.name).to.contain('myname'); + expect(input.value).to.contain('myvalue'); + }); + + it('invoke onChange', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(e.target.checked).to.be.true; + done(); + }}/>, + container); + }); + + let input = document.querySelector('input'); + input.checked = true; + ReactTestUtils.Simulate.change(input); + }); + }); + + context("type=textarea", () => { + it('renders textarea button', () => { + ReactTestUtils.act(() => { + ReactDOM.render( + , + container); + }); + + let label = document.querySelector('label'); + let textarea = document.querySelector('textarea'); + let error = document.querySelector('.settings-ui-input-error'); + expect(label.textContent).to.contain('myfield'); + expect(textarea.nodeName).to.contain('TEXTAREA'); + expect(textarea.name).to.contain('myname'); + expect(textarea.value).to.contain('myvalue'); + expect(error.textContent).to.contain('myerror'); + }); + + it('invoke onChange', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(e.target.value).to.equal('newvalue'); + done(); + }}/>, container); + }); + + let input = document.querySelector('textarea'); + input.value = 'newvalue' + ReactTestUtils.Simulate.change(input); + }); + }); +}); diff --git a/test/settings/reducers/setting.test.js b/test/settings/reducers/setting.test.js deleted file mode 100644 index c1a1648..0000000 --- a/test/settings/reducers/setting.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import actions from 'settings/actions'; -import settingReducer from 'settings/reducers/setting'; - -describe("settings setting reducer", () => { - it('return the initial state', () => { - let state = settingReducer(undefined, {}); - expect(state).to.have.deep.property('json', ''); - expect(state).to.have.deep.property('form', null); - expect(state).to.have.deep.property('error', ''); - }); - - it('return next state for SETTING_SET_SETTINGS', () => { - let action = { - type: actions.SETTING_SET_SETTINGS, - source: 'json', - json: '{ "key": "value" }', - form: {}, - }; - let state = settingReducer(undefined, action); - expect(state).to.have.deep.property('source', 'json'); - expect(state).to.have.deep.property('json', '{ "key": "value" }'); - expect(state).to.have.deep.property('form', {}); - }); - - it('return next state for SETTING_SHOW_ERROR', () => { - let action = { - type: actions.SETTING_SHOW_ERROR, - error: 'bad value', - json: '{}', - }; - let state = settingReducer(undefined, action); - expect(state).to.have.deep.property('error', 'bad value'); - expect(state).to.have.deep.property('json', '{}'); - }); - - it('return next state for SETTING_SWITCH_TO_FORM', () => { - let action = { - type: actions.SETTING_SWITCH_TO_FORM, - form: {}, - }; - let state = settingReducer(undefined, action); - expect(state).to.have.deep.property('form', {}); - expect(state).to.have.deep.property('source', 'form'); - }); - - it('return next state for SETTING_SWITCH_TO_JSON', () => { - let action = { - type: actions.SETTING_SWITCH_TO_JSON, - json: '{}', - }; - let state = settingReducer(undefined, action); - expect(state).to.have.deep.property('json', '{}'); - expect(state).to.have.deep.property('source', 'json'); - }); -}); diff --git a/test/settings/reducers/setting.test.ts b/test/settings/reducers/setting.test.ts new file mode 100644 index 0000000..c1a1648 --- /dev/null +++ b/test/settings/reducers/setting.test.ts @@ -0,0 +1,55 @@ +import actions from 'settings/actions'; +import settingReducer from 'settings/reducers/setting'; + +describe("settings setting reducer", () => { + it('return the initial state', () => { + let state = settingReducer(undefined, {}); + expect(state).to.have.deep.property('json', ''); + expect(state).to.have.deep.property('form', null); + expect(state).to.have.deep.property('error', ''); + }); + + it('return next state for SETTING_SET_SETTINGS', () => { + let action = { + type: actions.SETTING_SET_SETTINGS, + source: 'json', + json: '{ "key": "value" }', + form: {}, + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('source', 'json'); + expect(state).to.have.deep.property('json', '{ "key": "value" }'); + expect(state).to.have.deep.property('form', {}); + }); + + it('return next state for SETTING_SHOW_ERROR', () => { + let action = { + type: actions.SETTING_SHOW_ERROR, + error: 'bad value', + json: '{}', + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('error', 'bad value'); + expect(state).to.have.deep.property('json', '{}'); + }); + + it('return next state for SETTING_SWITCH_TO_FORM', () => { + let action = { + type: actions.SETTING_SWITCH_TO_FORM, + form: {}, + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('form', {}); + expect(state).to.have.deep.property('source', 'form'); + }); + + it('return next state for SETTING_SWITCH_TO_JSON', () => { + let action = { + type: actions.SETTING_SWITCH_TO_JSON, + json: '{}', + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('json', '{}'); + expect(state).to.have.deep.property('source', 'json'); + }); +}); diff --git a/test/shared/blacklists.test.js b/test/shared/blacklists.test.js deleted file mode 100644 index 289ea0f..0000000 --- a/test/shared/blacklists.test.js +++ /dev/null @@ -1,49 +0,0 @@ -import { includes } from 'shared/blacklists'; - -describe("shared/blacklist", () => { - it('matches by *', () => { - let blacklist = ['*']; - - expect(includes(blacklist, 'https://github.com/abc')).to.be.true; - }) - - it('matches by hostname', () => { - let blacklist = ['github.com']; - - expect(includes(blacklist, 'https://github.com')).to.be.true; - expect(includes(blacklist, 'https://gist.github.com')).to.be.false; - expect(includes(blacklist, 'https://github.com/ueokande')).to.be.true; - expect(includes(blacklist, 'https://github.org')).to.be.false; - expect(includes(blacklist, 'https://google.com/search?q=github.org')).to.be.false; - }) - - it('matches by hostname with wildcard', () => { - let blacklist = ['*.github.com']; - - expect(includes(blacklist, 'https://github.com')).to.be.false; - expect(includes(blacklist, 'https://gist.github.com')).to.be.true; - }) - - it('matches by path', () => { - let blacklist = ['github.com/abc']; - - expect(includes(blacklist, 'https://github.com/abc')).to.be.true; - expect(includes(blacklist, 'https://github.com/abcdef')).to.be.false; - expect(includes(blacklist, 'https://gist.github.com/abc')).to.be.false; - }) - - it('matches by path with wildcard', () => { - let blacklist = ['github.com/abc*']; - - expect(includes(blacklist, 'https://github.com/abc')).to.be.true; - expect(includes(blacklist, 'https://github.com/abcdef')).to.be.true; - expect(includes(blacklist, 'https://gist.github.com/abc')).to.be.false; - }) - - it('matches address and port', () => { - let blacklist = ['127.0.0.1:8888']; - - expect(includes(blacklist, 'http://127.0.0.1:8888/')).to.be.true; - expect(includes(blacklist, 'http://127.0.0.1:8888/hello')).to.be.true; - }) -}); diff --git a/test/shared/blacklists.test.ts b/test/shared/blacklists.test.ts new file mode 100644 index 0000000..289ea0f --- /dev/null +++ b/test/shared/blacklists.test.ts @@ -0,0 +1,49 @@ +import { includes } from 'shared/blacklists'; + +describe("shared/blacklist", () => { + it('matches by *', () => { + let blacklist = ['*']; + + expect(includes(blacklist, 'https://github.com/abc')).to.be.true; + }) + + it('matches by hostname', () => { + let blacklist = ['github.com']; + + expect(includes(blacklist, 'https://github.com')).to.be.true; + expect(includes(blacklist, 'https://gist.github.com')).to.be.false; + expect(includes(blacklist, 'https://github.com/ueokande')).to.be.true; + expect(includes(blacklist, 'https://github.org')).to.be.false; + expect(includes(blacklist, 'https://google.com/search?q=github.org')).to.be.false; + }) + + it('matches by hostname with wildcard', () => { + let blacklist = ['*.github.com']; + + expect(includes(blacklist, 'https://github.com')).to.be.false; + expect(includes(blacklist, 'https://gist.github.com')).to.be.true; + }) + + it('matches by path', () => { + let blacklist = ['github.com/abc']; + + expect(includes(blacklist, 'https://github.com/abc')).to.be.true; + expect(includes(blacklist, 'https://github.com/abcdef')).to.be.false; + expect(includes(blacklist, 'https://gist.github.com/abc')).to.be.false; + }) + + it('matches by path with wildcard', () => { + let blacklist = ['github.com/abc*']; + + expect(includes(blacklist, 'https://github.com/abc')).to.be.true; + expect(includes(blacklist, 'https://github.com/abcdef')).to.be.true; + expect(includes(blacklist, 'https://gist.github.com/abc')).to.be.false; + }) + + it('matches address and port', () => { + let blacklist = ['127.0.0.1:8888']; + + expect(includes(blacklist, 'http://127.0.0.1:8888/')).to.be.true; + expect(includes(blacklist, 'http://127.0.0.1:8888/hello')).to.be.true; + }) +}); diff --git a/test/shared/settings/validator.test.js b/test/shared/settings/validator.test.js deleted file mode 100644 index 9bbfa3e..0000000 --- a/test/shared/settings/validator.test.js +++ /dev/null @@ -1,81 +0,0 @@ -import { validate } from 'shared/settings/validator'; - -describe("setting validator", () => { - describe("unknown top keys", () => { - it('throws an error for unknown settings', () => { - let settings = { keymaps: {}, poison: 123 }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'poison'); - }) - }); - - describe("keymaps settings", () => { - it('throws an error for unknown operation', () => { - let settings = { - keymaps: { - a: { 'type': 'scroll.home' }, - b: { 'type': 'poison.dressing' }, - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'poison.dressing'); - }); - }); - - describe("search settings", () => { - it('throws an error for invalid search engine name', () => { - let settings = { - search: { - default: 'google', - engines: { - 'google': 'https://google.com/search?q={}', - 'cherry pie': 'https://cherypie.com/search?q={}', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'cherry pie'); - }); - - it('throws an error for no {}-placeholder', () => { - let settings = { - search: { - default: 'google', - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'yahoo'); - }); - - it('throws an error for no default engines', () => { - let settings = { - search: { - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?q={}', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'Default engine'); - }); - - it('throws an error for invalid default engine', () => { - let settings = { - search: { - default: 'twitter', - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?q={}', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'twitter'); - }); - }); -}); diff --git a/test/shared/settings/validator.test.ts b/test/shared/settings/validator.test.ts new file mode 100644 index 0000000..9bbfa3e --- /dev/null +++ b/test/shared/settings/validator.test.ts @@ -0,0 +1,81 @@ +import { validate } from 'shared/settings/validator'; + +describe("setting validator", () => { + describe("unknown top keys", () => { + it('throws an error for unknown settings', () => { + let settings = { keymaps: {}, poison: 123 }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'poison'); + }) + }); + + describe("keymaps settings", () => { + it('throws an error for unknown operation', () => { + let settings = { + keymaps: { + a: { 'type': 'scroll.home' }, + b: { 'type': 'poison.dressing' }, + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'poison.dressing'); + }); + }); + + describe("search settings", () => { + it('throws an error for invalid search engine name', () => { + let settings = { + search: { + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'cherry pie': 'https://cherypie.com/search?q={}', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'cherry pie'); + }); + + it('throws an error for no {}-placeholder', () => { + let settings = { + search: { + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'yahoo'); + }); + + it('throws an error for no default engines', () => { + let settings = { + search: { + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?q={}', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'Default engine'); + }); + + it('throws an error for invalid default engine', () => { + let settings = { + search: { + default: 'twitter', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?q={}', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'twitter'); + }); + }); +}); diff --git a/test/shared/settings/values.test.js b/test/shared/settings/values.test.js deleted file mode 100644 index c72824d..0000000 --- a/test/shared/settings/values.test.js +++ /dev/null @@ -1,138 +0,0 @@ -import * as values from 'shared/settings/values'; - -describe("settings values", () => { - describe('valueFromJson', () => { - it('return object from json string', () => { - let json = `{ - "keymaps": { "0": {"type": "scroll.home"}}, - "search": { "default": "google", "engines": { "google": "https://google.com/search?q={}" }}, - "blacklist": [ "*.slack.com"], - "properties": { - "mystr": "value", - "mynum": 123, - "mybool": true - } - }`; - let value = values.valueFromJson(json); - - expect(value.keymaps).to.deep.equal({ 0: {type: "scroll.home"}}); - expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); - expect(value.blacklist).to.deep.equal(["*.slack.com"]); - expect(value.properties).to.have.property('mystr', 'value'); - expect(value.properties).to.have.property('mynum', 123); - expect(value.properties).to.have.property('mybool', true); - }); - }); - - describe('valueFromForm', () => { - it('returns value from form', () => { - let form = { - keymaps: { - 'scroll.vertically?{"count":1}': 'j', - 'scroll.home': '0', - }, - search: { - default: 'google', - engines: [['google', 'https://google.com/search?q={}']], - }, - blacklist: ['*.slack.com'], - "properties": { - "mystr": "value", - "mynum": 123, - "mybool": true, - } - }; - let value = values.valueFromForm(form); - - expect(value.keymaps).to.have.deep.property('j', { type: "scroll.vertically", count: 1 }); - expect(value.keymaps).to.have.deep.property('0', { type: "scroll.home" }); - expect(JSON.stringify(value.search)).to.deep.equal(JSON.stringify({ default: "google", engines: { google: "https://google.com/search?q={}"} })); - expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); - expect(value.blacklist).to.deep.equal(["*.slack.com"]); - expect(value.properties).to.have.property('mystr', 'value'); - expect(value.properties).to.have.property('mynum', 123); - expect(value.properties).to.have.property('mybool', true); - }); - - it('convert from empty form', () => { - let form = {}; - let value = values.valueFromForm(form); - expect(value).to.not.have.key('keymaps'); - expect(value).to.not.have.key('search'); - expect(value).to.not.have.key('blacklist'); - expect(value).to.not.have.key('properties'); - }); - - it('override keymaps', () => { - let form = { - keymaps: { - 'scroll.vertically?{"count":1}': 'j', - 'scroll.vertically?{"count":-1}': 'j', - } - }; - let value = values.valueFromForm(form); - - expect(value.keymaps).to.have.key('j'); - }); - - it('override search engine', () => { - let form = { - search: { - default: 'google', - engines: [ - ['google', 'https://google.com/search?q={}'], - ['google', 'https://google.co.jp/search?q={}'], - ] - } - }; - let value = values.valueFromForm(form); - - expect(value.search.engines).to.have.property('google', 'https://google.co.jp/search?q={}'); - }); - }); - - describe('jsonFromValue', () => { - }); - - describe('formFromValue', () => { - it('convert empty value to form', () => { - let value = {}; - let form = values.formFromValue(value); - - expect(value).to.not.have.key('keymaps'); - expect(value).to.not.have.key('search'); - expect(value).to.not.have.key('blacklist'); - }); - - it('convert value to form', () => { - let value = { - keymaps: { - j: { type: 'scroll.vertically', count: 1 }, - JJ: { type: 'scroll.vertically', count: 100 }, - 0: { type: 'scroll.home' }, - }, - search: { default: 'google', engines: { google: 'https://google.com/search?q={}' }}, - blacklist: [ '*.slack.com'], - properties: { - "mystr": "value", - "mynum": 123, - "mybool": true, - } - }; - let allowed = ['scroll.vertically?{"count":1}', 'scroll.home' ]; - let form = values.formFromValue(value, allowed); - - expect(form.keymaps).to.have.property('scroll.vertically?{"count":1}', 'j'); - expect(form.keymaps).to.not.have.property('scroll.vertically?{"count":100}'); - expect(form.keymaps).to.have.property('scroll.home', '0'); - expect(Object.keys(form.keymaps)).to.have.lengthOf(2); - expect(form.search).to.have.property('default', 'google'); - expect(form.search).to.have.deep.property('engines', [['google', 'https://google.com/search?q={}']]); - expect(form.blacklist).to.have.lengthOf(1); - expect(form.blacklist).to.include('*.slack.com'); - expect(form.properties).to.have.property('mystr', 'value'); - expect(form.properties).to.have.property('mynum', 123); - expect(form.properties).to.have.property('mybool', true); - }); - }); -}); diff --git a/test/shared/settings/values.test.ts b/test/shared/settings/values.test.ts new file mode 100644 index 0000000..c72824d --- /dev/null +++ b/test/shared/settings/values.test.ts @@ -0,0 +1,138 @@ +import * as values from 'shared/settings/values'; + +describe("settings values", () => { + describe('valueFromJson', () => { + it('return object from json string', () => { + let json = `{ + "keymaps": { "0": {"type": "scroll.home"}}, + "search": { "default": "google", "engines": { "google": "https://google.com/search?q={}" }}, + "blacklist": [ "*.slack.com"], + "properties": { + "mystr": "value", + "mynum": 123, + "mybool": true + } + }`; + let value = values.valueFromJson(json); + + expect(value.keymaps).to.deep.equal({ 0: {type: "scroll.home"}}); + expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); + expect(value.blacklist).to.deep.equal(["*.slack.com"]); + expect(value.properties).to.have.property('mystr', 'value'); + expect(value.properties).to.have.property('mynum', 123); + expect(value.properties).to.have.property('mybool', true); + }); + }); + + describe('valueFromForm', () => { + it('returns value from form', () => { + let form = { + keymaps: { + 'scroll.vertically?{"count":1}': 'j', + 'scroll.home': '0', + }, + search: { + default: 'google', + engines: [['google', 'https://google.com/search?q={}']], + }, + blacklist: ['*.slack.com'], + "properties": { + "mystr": "value", + "mynum": 123, + "mybool": true, + } + }; + let value = values.valueFromForm(form); + + expect(value.keymaps).to.have.deep.property('j', { type: "scroll.vertically", count: 1 }); + expect(value.keymaps).to.have.deep.property('0', { type: "scroll.home" }); + expect(JSON.stringify(value.search)).to.deep.equal(JSON.stringify({ default: "google", engines: { google: "https://google.com/search?q={}"} })); + expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); + expect(value.blacklist).to.deep.equal(["*.slack.com"]); + expect(value.properties).to.have.property('mystr', 'value'); + expect(value.properties).to.have.property('mynum', 123); + expect(value.properties).to.have.property('mybool', true); + }); + + it('convert from empty form', () => { + let form = {}; + let value = values.valueFromForm(form); + expect(value).to.not.have.key('keymaps'); + expect(value).to.not.have.key('search'); + expect(value).to.not.have.key('blacklist'); + expect(value).to.not.have.key('properties'); + }); + + it('override keymaps', () => { + let form = { + keymaps: { + 'scroll.vertically?{"count":1}': 'j', + 'scroll.vertically?{"count":-1}': 'j', + } + }; + let value = values.valueFromForm(form); + + expect(value.keymaps).to.have.key('j'); + }); + + it('override search engine', () => { + let form = { + search: { + default: 'google', + engines: [ + ['google', 'https://google.com/search?q={}'], + ['google', 'https://google.co.jp/search?q={}'], + ] + } + }; + let value = values.valueFromForm(form); + + expect(value.search.engines).to.have.property('google', 'https://google.co.jp/search?q={}'); + }); + }); + + describe('jsonFromValue', () => { + }); + + describe('formFromValue', () => { + it('convert empty value to form', () => { + let value = {}; + let form = values.formFromValue(value); + + expect(value).to.not.have.key('keymaps'); + expect(value).to.not.have.key('search'); + expect(value).to.not.have.key('blacklist'); + }); + + it('convert value to form', () => { + let value = { + keymaps: { + j: { type: 'scroll.vertically', count: 1 }, + JJ: { type: 'scroll.vertically', count: 100 }, + 0: { type: 'scroll.home' }, + }, + search: { default: 'google', engines: { google: 'https://google.com/search?q={}' }}, + blacklist: [ '*.slack.com'], + properties: { + "mystr": "value", + "mynum": 123, + "mybool": true, + } + }; + let allowed = ['scroll.vertically?{"count":1}', 'scroll.home' ]; + let form = values.formFromValue(value, allowed); + + expect(form.keymaps).to.have.property('scroll.vertically?{"count":1}', 'j'); + expect(form.keymaps).to.not.have.property('scroll.vertically?{"count":100}'); + expect(form.keymaps).to.have.property('scroll.home', '0'); + expect(Object.keys(form.keymaps)).to.have.lengthOf(2); + expect(form.search).to.have.property('default', 'google'); + expect(form.search).to.have.deep.property('engines', [['google', 'https://google.com/search?q={}']]); + expect(form.blacklist).to.have.lengthOf(1); + expect(form.blacklist).to.include('*.slack.com'); + expect(form.properties).to.have.property('mystr', 'value'); + expect(form.properties).to.have.property('mynum', 123); + expect(form.properties).to.have.property('mybool', true); + }); + }); +}); diff --git a/test/shared/urls.test.js b/test/shared/urls.test.js deleted file mode 100644 index f2950b6..0000000 --- a/test/shared/urls.test.js +++ /dev/null @@ -1,48 +0,0 @@ -import * as parsers from 'shared/urls'; - -describe("shared/commands/parsers", () => { - describe('#searchUrl', () => { - const config = { - default: 'google', - engines: { - google: 'https://google.com/search?q={}', - yahoo: 'https://yahoo.com/search?q={}', - } - }; - - it('convertes search url', () => { - expect(parsers.searchUrl('google.com', config)) - .to.equal('http://google.com'); - expect(parsers.searchUrl('google apple', config)) - .to.equal('https://google.com/search?q=apple'); - expect(parsers.searchUrl('yahoo apple', config)) - .to.equal('https://yahoo.com/search?q=apple'); - expect(parsers.searchUrl('google apple banana', config)) - .to.equal('https://google.com/search?q=apple%20banana'); - expect(parsers.searchUrl('yahoo C++CLI', config)) - .to.equal('https://yahoo.com/search?q=C%2B%2BCLI'); - }); - - it('user default search engine', () => { - expect(parsers.searchUrl('apple banana', config)) - .to.equal('https://google.com/search?q=apple%20banana'); - }); - - it('searches with a word containing a colon', () => { - expect(parsers.searchUrl('foo:', config)) - .to.equal('https://google.com/search?q=foo%3A'); - expect(parsers.searchUrl('std::vector', config)) - .to.equal('https://google.com/search?q=std%3A%3Avector'); - }); - }); - - describe('#normalizeUrl', () => { - it('normalize urls', () => { - expect(parsers.normalizeUrl('https://google.com/')) - .to.equal('https://google.com/'); - expect(parsers.normalizeUrl('google.com')) - .to.equal('http://google.com'); - }); - }); -}); - diff --git a/test/shared/urls.test.ts b/test/shared/urls.test.ts new file mode 100644 index 0000000..f2950b6 --- /dev/null +++ b/test/shared/urls.test.ts @@ -0,0 +1,48 @@ +import * as parsers from 'shared/urls'; + +describe("shared/commands/parsers", () => { + describe('#searchUrl', () => { + const config = { + default: 'google', + engines: { + google: 'https://google.com/search?q={}', + yahoo: 'https://yahoo.com/search?q={}', + } + }; + + it('convertes search url', () => { + expect(parsers.searchUrl('google.com', config)) + .to.equal('http://google.com'); + expect(parsers.searchUrl('google apple', config)) + .to.equal('https://google.com/search?q=apple'); + expect(parsers.searchUrl('yahoo apple', config)) + .to.equal('https://yahoo.com/search?q=apple'); + expect(parsers.searchUrl('google apple banana', config)) + .to.equal('https://google.com/search?q=apple%20banana'); + expect(parsers.searchUrl('yahoo C++CLI', config)) + .to.equal('https://yahoo.com/search?q=C%2B%2BCLI'); + }); + + it('user default search engine', () => { + expect(parsers.searchUrl('apple banana', config)) + .to.equal('https://google.com/search?q=apple%20banana'); + }); + + it('searches with a word containing a colon', () => { + expect(parsers.searchUrl('foo:', config)) + .to.equal('https://google.com/search?q=foo%3A'); + expect(parsers.searchUrl('std::vector', config)) + .to.equal('https://google.com/search?q=std%3A%3Avector'); + }); + }); + + describe('#normalizeUrl', () => { + it('normalize urls', () => { + expect(parsers.normalizeUrl('https://google.com/')) + .to.equal('https://google.com/'); + expect(parsers.normalizeUrl('google.com')) + .to.equal('http://google.com'); + }); + }); +}); + diff --git a/test/shared/utils/keys.test.js b/test/shared/utils/keys.test.js deleted file mode 100644 index b2ad3cb..0000000 --- a/test/shared/utils/keys.test.js +++ /dev/null @@ -1,164 +0,0 @@ -import * as keys from 'shared/utils/keys'; - -describe("keys util", () => { - describe('fromKeyboardEvent', () => { - it('returns from keyboard input Ctrl+X', () => { - let k = keys.fromKeyboardEvent({ - key: 'x', shiftKey: false, ctrlKey: true, altKey: false, metaKey: true - }); - expect(k.key).to.equal('x'); - expect(k.shiftKey).to.be.false; - expect(k.ctrlKey).to.be.true; - expect(k.altKey).to.be.false; - expect(k.metaKey).to.be.true; - }); - - it('returns from keyboard input Shift+Esc', () => { - let k = keys.fromKeyboardEvent({ - key: 'Escape', shiftKey: true, ctrlKey: false, altKey: false, metaKey: true - }); - expect(k.key).to.equal('Esc'); - expect(k.shiftKey).to.be.true; - expect(k.ctrlKey).to.be.false; - expect(k.altKey).to.be.false; - expect(k.metaKey).to.be.true; - }); - - it('returns from keyboard input Ctrl+$', () => { - // $ required shift pressing on most keyboards - let k = keys.fromKeyboardEvent({ - key: '$', shiftKey: true, ctrlKey: true, altKey: false, metaKey: false - }); - expect(k.key).to.equal('$'); - expect(k.shiftKey).to.be.false; - expect(k.ctrlKey).to.be.true; - expect(k.altKey).to.be.false; - expect(k.metaKey).to.be.false; - }); - - it('returns from keyboard input Crtl+Space', () => { - let k = keys.fromKeyboardEvent({ - key: ' ', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false - }); - expect(k.key).to.equal('Space'); - expect(k.shiftKey).to.be.false; - expect(k.ctrlKey).to.be.true; - expect(k.altKey).to.be.false; - expect(k.metaKey).to.be.false; - }); - }); - - describe('fromMapKey', () => { - it('return for X', () => { - let key = keys.fromMapKey('x'); - expect(key.key).to.equal('x'); - expect(key.shiftKey).to.be.false; - expect(key.ctrlKey).to.be.false; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - - it('return for Shift+X', () => { - let key = keys.fromMapKey('X'); - expect(key.key).to.equal('X'); - expect(key.shiftKey).to.be.true; - expect(key.ctrlKey).to.be.false; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - - it('return for Ctrl+X', () => { - let key = keys.fromMapKey(''); - expect(key.key).to.equal('x'); - expect(key.shiftKey).to.be.false; - expect(key.ctrlKey).to.be.true; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - - it('returns for Ctrl+Meta+X', () => { - let key = keys.fromMapKey(''); - expect(key.key).to.equal('x'); - expect(key.shiftKey).to.be.false; - expect(key.ctrlKey).to.be.true; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.true; - }); - - it('returns for Ctrl+Shift+x', () => { - let key = keys.fromMapKey(''); - expect(key.key).to.equal('X'); - expect(key.shiftKey).to.be.true; - expect(key.ctrlKey).to.be.true; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - - it('returns for Shift+Esc', () => { - let key = keys.fromMapKey(''); - expect(key.key).to.equal('Esc'); - expect(key.shiftKey).to.be.true; - expect(key.ctrlKey).to.be.false; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - - it('returns for Ctrl+Esc', () => { - let key = keys.fromMapKey(''); - expect(key.key).to.equal('Esc'); - expect(key.shiftKey).to.be.false; - expect(key.ctrlKey).to.be.true; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - - it('returns for Ctrl+Esc', () => { - let key = keys.fromMapKey(''); - expect(key.key).to.equal('Space'); - expect(key.shiftKey).to.be.false; - expect(key.ctrlKey).to.be.true; - expect(key.altKey).to.be.false; - expect(key.metaKey).to.be.false; - }); - }); - - describe('fromMapKeys', () => { - it('returns mapped keys for Shift+Esc', () => { - let keyArray = keys.fromMapKeys(''); - expect(keyArray).to.have.lengthOf(1); - expect(keyArray[0].key).to.equal('Esc'); - expect(keyArray[0].shiftKey).to.be.true; - }); - - it('returns mapped keys for ad', () => { - let keyArray = keys.fromMapKeys('ad'); - expect(keyArray).to.have.lengthOf(5); - expect(keyArray[0].key).to.equal('a'); - expect(keyArray[1].ctrlKey).to.be.true; - expect(keyArray[1].key).to.equal('b'); - expect(keyArray[2].altKey).to.be.true; - expect(keyArray[2].key).to.equal('c'); - expect(keyArray[3].key).to.equal('d'); - expect(keyArray[4].metaKey).to.be.true; - expect(keyArray[4].key).to.equal('e'); - }); - }) - - describe('equals', () => { - expect(keys.equals({ - key: 'x', - ctrlKey: true, - }, { - key: 'x', - ctrlKey: true, - })).to.be.true; - - expect(keys.equals({ - key: 'X', - shiftKey: true, - }, { - key: 'x', - ctrlKey: true, - })).to.be.false; - }); -}); diff --git a/test/shared/utils/keys.test.ts b/test/shared/utils/keys.test.ts new file mode 100644 index 0000000..b2ad3cb --- /dev/null +++ b/test/shared/utils/keys.test.ts @@ -0,0 +1,164 @@ +import * as keys from 'shared/utils/keys'; + +describe("keys util", () => { + describe('fromKeyboardEvent', () => { + it('returns from keyboard input Ctrl+X', () => { + let k = keys.fromKeyboardEvent({ + key: 'x', shiftKey: false, ctrlKey: true, altKey: false, metaKey: true + }); + expect(k.key).to.equal('x'); + expect(k.shiftKey).to.be.false; + expect(k.ctrlKey).to.be.true; + expect(k.altKey).to.be.false; + expect(k.metaKey).to.be.true; + }); + + it('returns from keyboard input Shift+Esc', () => { + let k = keys.fromKeyboardEvent({ + key: 'Escape', shiftKey: true, ctrlKey: false, altKey: false, metaKey: true + }); + expect(k.key).to.equal('Esc'); + expect(k.shiftKey).to.be.true; + expect(k.ctrlKey).to.be.false; + expect(k.altKey).to.be.false; + expect(k.metaKey).to.be.true; + }); + + it('returns from keyboard input Ctrl+$', () => { + // $ required shift pressing on most keyboards + let k = keys.fromKeyboardEvent({ + key: '$', shiftKey: true, ctrlKey: true, altKey: false, metaKey: false + }); + expect(k.key).to.equal('$'); + expect(k.shiftKey).to.be.false; + expect(k.ctrlKey).to.be.true; + expect(k.altKey).to.be.false; + expect(k.metaKey).to.be.false; + }); + + it('returns from keyboard input Crtl+Space', () => { + let k = keys.fromKeyboardEvent({ + key: ' ', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false + }); + expect(k.key).to.equal('Space'); + expect(k.shiftKey).to.be.false; + expect(k.ctrlKey).to.be.true; + expect(k.altKey).to.be.false; + expect(k.metaKey).to.be.false; + }); + }); + + describe('fromMapKey', () => { + it('return for X', () => { + let key = keys.fromMapKey('x'); + expect(key.key).to.equal('x'); + expect(key.shiftKey).to.be.false; + expect(key.ctrlKey).to.be.false; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + + it('return for Shift+X', () => { + let key = keys.fromMapKey('X'); + expect(key.key).to.equal('X'); + expect(key.shiftKey).to.be.true; + expect(key.ctrlKey).to.be.false; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + + it('return for Ctrl+X', () => { + let key = keys.fromMapKey(''); + expect(key.key).to.equal('x'); + expect(key.shiftKey).to.be.false; + expect(key.ctrlKey).to.be.true; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + + it('returns for Ctrl+Meta+X', () => { + let key = keys.fromMapKey(''); + expect(key.key).to.equal('x'); + expect(key.shiftKey).to.be.false; + expect(key.ctrlKey).to.be.true; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.true; + }); + + it('returns for Ctrl+Shift+x', () => { + let key = keys.fromMapKey(''); + expect(key.key).to.equal('X'); + expect(key.shiftKey).to.be.true; + expect(key.ctrlKey).to.be.true; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + + it('returns for Shift+Esc', () => { + let key = keys.fromMapKey(''); + expect(key.key).to.equal('Esc'); + expect(key.shiftKey).to.be.true; + expect(key.ctrlKey).to.be.false; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + + it('returns for Ctrl+Esc', () => { + let key = keys.fromMapKey(''); + expect(key.key).to.equal('Esc'); + expect(key.shiftKey).to.be.false; + expect(key.ctrlKey).to.be.true; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + + it('returns for Ctrl+Esc', () => { + let key = keys.fromMapKey(''); + expect(key.key).to.equal('Space'); + expect(key.shiftKey).to.be.false; + expect(key.ctrlKey).to.be.true; + expect(key.altKey).to.be.false; + expect(key.metaKey).to.be.false; + }); + }); + + describe('fromMapKeys', () => { + it('returns mapped keys for Shift+Esc', () => { + let keyArray = keys.fromMapKeys(''); + expect(keyArray).to.have.lengthOf(1); + expect(keyArray[0].key).to.equal('Esc'); + expect(keyArray[0].shiftKey).to.be.true; + }); + + it('returns mapped keys for ad', () => { + let keyArray = keys.fromMapKeys('ad'); + expect(keyArray).to.have.lengthOf(5); + expect(keyArray[0].key).to.equal('a'); + expect(keyArray[1].ctrlKey).to.be.true; + expect(keyArray[1].key).to.equal('b'); + expect(keyArray[2].altKey).to.be.true; + expect(keyArray[2].key).to.equal('c'); + expect(keyArray[3].key).to.equal('d'); + expect(keyArray[4].metaKey).to.be.true; + expect(keyArray[4].key).to.equal('e'); + }); + }) + + describe('equals', () => { + expect(keys.equals({ + key: 'x', + ctrlKey: true, + }, { + key: 'x', + ctrlKey: true, + })).to.be.true; + + expect(keys.equals({ + key: 'X', + shiftKey: true, + }, { + key: 'x', + ctrlKey: true, + })).to.be.false; + }); +}); diff --git a/test/shared/utils/re.test.js b/test/shared/utils/re.test.js deleted file mode 100644 index d12ceb7..0000000 --- a/test/shared/utils/re.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import * as re from 'shared/utils/re'; - -describe("re util", () => { - it('matches by pattern', () => { - let regex = re.fromWildcard('*.example.com/*'); - expect('foo.example.com/bar').to.match(regex); - expect('foo.example.com').not.to.match(regex); - expect('example.com/bar').not.to.match(regex); - - regex = re.fromWildcard('example.com/*') - expect('example.com/foo').to.match(regex); - expect('example.com/').to.match(regex); - - regex = re.fromWildcard('example.com/*bar') - expect('example.com/foobar').to.match(regex); - expect('example.com/bar').to.match(regex); - expect('example.com/foobarfoo').not.to.match(regex); - }) -}); diff --git a/test/shared/utils/re.test.ts b/test/shared/utils/re.test.ts new file mode 100644 index 0000000..d12ceb7 --- /dev/null +++ b/test/shared/utils/re.test.ts @@ -0,0 +1,19 @@ +import * as re from 'shared/utils/re'; + +describe("re util", () => { + it('matches by pattern', () => { + let regex = re.fromWildcard('*.example.com/*'); + expect('foo.example.com/bar').to.match(regex); + expect('foo.example.com').not.to.match(regex); + expect('example.com/bar').not.to.match(regex); + + regex = re.fromWildcard('example.com/*') + expect('example.com/foo').to.match(regex); + expect('example.com/').to.match(regex); + + regex = re.fromWildcard('example.com/*bar') + expect('example.com/foobar').to.match(regex); + expect('example.com/bar').to.match(regex); + expect('example.com/foobarfoo').not.to.match(regex); + }) +}); -- cgit v1.2.3 From 678020a3a27713e77ec8d74483122b4258fbc829 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 1 May 2019 11:04:24 +0900 Subject: Types on src/background --- .../controllers/AddonEnabledController.ts | 4 +- src/background/controllers/CommandController.ts | 14 ++- src/background/controllers/FindController.ts | 6 +- src/background/controllers/LinkController.ts | 12 ++- src/background/controllers/MarkController.ts | 10 +- src/background/controllers/OperationController.ts | 13 ++- src/background/controllers/SettingController.ts | 8 +- src/background/controllers/VersionController.ts | 6 +- src/background/controllers/version.ts | 13 --- src/background/domains/CommandDocs.ts | 3 +- src/background/domains/CompletionGroup.ts | 17 +--- src/background/domains/CompletionItem.ts | 29 ++---- src/background/domains/Completions.ts | 27 ------ src/background/domains/GlobalMark.ts | 28 +----- src/background/infrastructures/ConsoleClient.ts | 10 +- .../infrastructures/ContentMessageClient.ts | 12 +-- .../infrastructures/ContentMessageListener.ts | 78 ++++++++++----- src/background/infrastructures/MemoryStorage.ts | 6 +- src/background/presenters/IndicatorPresenter.ts | 4 +- src/background/presenters/NotifyPresenter.ts | 8 +- src/background/presenters/TabPresenter.ts | 44 +++++---- src/background/presenters/WindowPresenter.ts | 2 +- src/background/repositories/BookmarkRepository.ts | 4 +- .../repositories/BrowserSettingRepository.ts | 2 +- .../repositories/CompletionsRepository.ts | 14 ++- src/background/repositories/FindRepository.ts | 6 +- src/background/repositories/MarkRepository.ts | 8 +- .../repositories/PersistentSettingRepository.ts | 2 +- src/background/repositories/SettingRepository.ts | 8 +- src/background/repositories/VersionRepository.ts | 10 -- src/background/usecases/AddonEnabledUseCase.ts | 18 +++- src/background/usecases/CommandUseCase.ts | 52 ++++++---- src/background/usecases/CompletionsUseCase.ts | 107 ++++++++++++--------- src/background/usecases/ConsoleUseCase.ts | 40 ++++---- src/background/usecases/FindUseCase.ts | 14 ++- src/background/usecases/LinkUseCase.ts | 8 +- src/background/usecases/MarkUseCase.ts | 20 ++-- src/background/usecases/SettingUseCase.ts | 8 +- src/background/usecases/TabSelectUseCase.ts | 24 ++--- src/background/usecases/TabUseCase.ts | 36 ++++--- src/background/usecases/VersionUseCase.ts | 10 +- src/background/usecases/ZoomUseCase.ts | 26 ++--- src/background/usecases/filters.ts | 38 ++++---- src/background/usecases/parsers.ts | 10 +- src/content/scrolls.ts | 10 -- test/background/domains/GlobalMark.test.ts | 11 --- test/background/repositories/Mark.test.ts | 3 +- test/background/repositories/Version.ts | 34 ------- 48 files changed, 446 insertions(+), 431 deletions(-) delete mode 100644 src/background/controllers/version.ts delete mode 100644 src/background/domains/Completions.ts delete mode 100644 src/background/repositories/VersionRepository.ts delete mode 100644 test/background/domains/GlobalMark.test.ts delete mode 100644 test/background/repositories/Version.ts (limited to 'test') diff --git a/src/background/controllers/AddonEnabledController.ts b/src/background/controllers/AddonEnabledController.ts index 9a3a521..251af25 100644 --- a/src/background/controllers/AddonEnabledController.ts +++ b/src/background/controllers/AddonEnabledController.ts @@ -1,11 +1,13 @@ import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; export default class AddonEnabledController { + private addonEnabledUseCase: AddonEnabledUseCase; + constructor() { this.addonEnabledUseCase = new AddonEnabledUseCase(); } - indicate(enabled) { + indicate(enabled: boolean): Promise { return this.addonEnabledUseCase.indicate(enabled); } } diff --git a/src/background/controllers/CommandController.ts b/src/background/controllers/CommandController.ts index b113709..f3a6b7f 100644 --- a/src/background/controllers/CommandController.ts +++ b/src/background/controllers/CommandController.ts @@ -1,19 +1,23 @@ import CompletionsUseCase from '../usecases/CompletionsUseCase'; import CommandUseCase from '../usecases/CommandUseCase'; -import Completions from '../domains/Completions'; +import CompletionGroup from '../domains/CompletionGroup'; -const trimStart = (str) => { +const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 return str.replace(/^\s+/, ''); }; export default class CommandController { + private completionsUseCase: CompletionsUseCase; + + private commandIndicator: CommandUseCase; + constructor() { this.completionsUseCase = new CompletionsUseCase(); this.commandIndicator = new CommandUseCase(); } - getCompletions(line) { + getCompletions(line: string): Promise { let trimmed = trimStart(line); let words = trimmed.split(/ +/); let name = words[0]; @@ -45,11 +49,11 @@ export default class CommandController { case 'set': return this.completionsUseCase.querySet(name, keywords); } - return Promise.resolve(Completions.empty()); + return Promise.resolve([]); } // eslint-disable-next-line complexity - exec(line) { + exec(line: string): Promise { let trimmed = trimStart(line); let words = trimmed.split(/ +/); let name = words[0]; diff --git a/src/background/controllers/FindController.ts b/src/background/controllers/FindController.ts index caeff98..28959e2 100644 --- a/src/background/controllers/FindController.ts +++ b/src/background/controllers/FindController.ts @@ -1,15 +1,17 @@ import FindUseCase from '../usecases/FindUseCase'; export default class FindController { + private findUseCase: FindUseCase; + constructor() { this.findUseCase = new FindUseCase(); } - getKeyword() { + getKeyword(): Promise { return this.findUseCase.getKeyword(); } - setKeyword(keyword) { + setKeyword(keyword: string): Promise { return this.findUseCase.setKeyword(keyword); } } diff --git a/src/background/controllers/LinkController.ts b/src/background/controllers/LinkController.ts index 7e395b1..707b28a 100644 --- a/src/background/controllers/LinkController.ts +++ b/src/background/controllers/LinkController.ts @@ -1,15 +1,19 @@ import LinkUseCase from '../usecases/LinkUseCase'; export default class LinkController { + private linkUseCase: LinkUseCase; + constructor() { this.linkUseCase = new LinkUseCase(); } - openToTab(url, tabId) { - this.linkUseCase.openToTab(url, tabId); + openToTab(url: string, tabId: number): Promise { + return this.linkUseCase.openToTab(url, tabId); } - openNewTab(url, openerId, background) { - this.linkUseCase.openNewTab(url, openerId, background); + openNewTab( + url: string, openerId: number, background: boolean, + ): Promise { + return this.linkUseCase.openNewTab(url, openerId, background); } } diff --git a/src/background/controllers/MarkController.ts b/src/background/controllers/MarkController.ts index 0478369..419a08b 100644 --- a/src/background/controllers/MarkController.ts +++ b/src/background/controllers/MarkController.ts @@ -1,15 +1,17 @@ import MarkUseCase from '../usecases/MarkUseCase'; export default class MarkController { + private markUseCase: MarkUseCase; + constructor() { this.markUseCase = new MarkUseCase(); } - setGlobal(key, x, y) { - this.markUseCase.setGlobal(key, x, y); + setGlobal(key: string, x: number, y: number): Promise { + return this.markUseCase.setGlobal(key, x, y); } - jumpGlobal(key) { - this.markUseCase.jumpGlobal(key); + jumpGlobal(key: string): Promise { + return this.markUseCase.jumpGlobal(key); } } diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts index 416aa9c..4e9c106 100644 --- a/src/background/controllers/OperationController.ts +++ b/src/background/controllers/OperationController.ts @@ -6,6 +6,16 @@ import TabSelectUseCase from '../usecases/TabSelectUseCase'; import ZoomUseCase from '../usecases/ZoomUseCase'; export default class OperationController { + private findUseCase: FindUseCase; + + private consoleUseCase: ConsoleUseCase; + + private tabUseCase: TabUseCase; + + private tabSelectUseCase: TabSelectUseCase; + + private zoomUseCase: ZoomUseCase; + constructor() { this.findUseCase = new FindUseCase(); this.consoleUseCase = new ConsoleUseCase(); @@ -15,7 +25,7 @@ export default class OperationController { } // eslint-disable-next-line complexity, max-lines-per-function - exec(operation) { + exec(operation: any): Promise { switch (operation.type) { case operations.TAB_CLOSE: return this.tabUseCase.close(false); @@ -72,6 +82,7 @@ export default class OperationController { case operations.CANCEL: return this.consoleUseCase.hideConsole(); } + throw new Error('unknown operation: ' + operation.type); } } diff --git a/src/background/controllers/SettingController.ts b/src/background/controllers/SettingController.ts index e895d72..f8b7302 100644 --- a/src/background/controllers/SettingController.ts +++ b/src/background/controllers/SettingController.ts @@ -2,16 +2,20 @@ import SettingUseCase from '../usecases/SettingUseCase'; import ContentMessageClient from '../infrastructures/ContentMessageClient'; export default class SettingController { + private settingUseCase: SettingUseCase; + + private contentMessageClient: ContentMessageClient; + constructor() { this.settingUseCase = new SettingUseCase(); this.contentMessageClient = new ContentMessageClient(); } - getSetting() { + getSetting(): any { return this.settingUseCase.get(); } - async reload() { + async reload(): Promise { await this.settingUseCase.reload(); this.contentMessageClient.broadcastSettingsChanged(); } diff --git a/src/background/controllers/VersionController.ts b/src/background/controllers/VersionController.ts index c596f9b..f402ed0 100644 --- a/src/background/controllers/VersionController.ts +++ b/src/background/controllers/VersionController.ts @@ -1,11 +1,13 @@ import VersionUseCase from '../usecases/VersionUseCase'; export default class VersionController { + private versionUseCase: VersionUseCase; + constructor() { this.versionUseCase = new VersionUseCase(); } - notify() { - this.versionUseCase.notify(); + notify(): void { + return this.versionUseCase.notify(); } } diff --git a/src/background/controllers/version.ts b/src/background/controllers/version.ts deleted file mode 100644 index ec0f634..0000000 --- a/src/background/controllers/version.ts +++ /dev/null @@ -1,13 +0,0 @@ -import VersionInteractor from '../usecases/version'; - -export default class VersionController { - constructor() { - this.versionInteractor = new VersionInteractor(); - } - - notifyIfUpdated() { - browser.runtime.onInstalled.addListener(() => { - return this.versionInteractor.notify(); - }); - } -} diff --git a/src/background/domains/CommandDocs.ts b/src/background/domains/CommandDocs.ts index 734c68e..25ea62a 100644 --- a/src/background/domains/CommandDocs.ts +++ b/src/background/domains/CommandDocs.ts @@ -8,5 +8,4 @@ export default { bdeletes: 'Close all tabs matched by keywords', quit: 'Close the current tab', quitall: 'Close all tabs', -}; - +} as {[key: string]: string}; diff --git a/src/background/domains/CompletionGroup.ts b/src/background/domains/CompletionGroup.ts index 1749d72..1eea7d8 100644 --- a/src/background/domains/CompletionGroup.ts +++ b/src/background/domains/CompletionGroup.ts @@ -1,14 +1,7 @@ -export default class CompletionGroup { - constructor(name, items) { - this.name0 = name; - this.items0 = items; - } +import CompletionItem from './CompletionItem'; - get name() { - return this.name0; - } - - get items() { - return this.items0; - } +export default interface CompletionGroup { + name: string; + items: CompletionItem[]; + // eslint-disable-next-line semi } diff --git a/src/background/domains/CompletionItem.ts b/src/background/domains/CompletionItem.ts index c7ad8a1..657efaa 100644 --- a/src/background/domains/CompletionItem.ts +++ b/src/background/domains/CompletionItem.ts @@ -1,24 +1,7 @@ -export default class CompletionItem { - constructor({ caption, content, url, icon }) { - this.caption0 = caption; - this.content0 = content; - this.url0 = url; - this.icon0 = icon; - } - - get caption() { - return this.caption0; - } - - get content() { - return this.content0; - } - - get url() { - return this.url0; - } - - get icon() { - return this.icon0; - } +export default interface CompletionItem { + readonly caption?: string; + readonly content?: string; + readonly url?: string; + readonly icon?: string; + // eslint-disable-next-line semi } diff --git a/src/background/domains/Completions.ts b/src/background/domains/Completions.ts deleted file mode 100644 index f399743..0000000 --- a/src/background/domains/Completions.ts +++ /dev/null @@ -1,27 +0,0 @@ -export default class Completions { - constructor(groups) { - this.g = groups; - } - - get groups() { - return this.g; - } - - serialize() { - return this.groups.map(group => ({ - name: group.name, - items: group.items.map(item => ({ - caption: item.caption, - content: item.content, - url: item.url, - icon: item.icon, - })), - })); - } - - static empty() { - return EMPTY_COMPLETIONS; - } -} - -let EMPTY_COMPLETIONS = new Completions([]); diff --git a/src/background/domains/GlobalMark.ts b/src/background/domains/GlobalMark.ts index f0586f1..0964373 100644 --- a/src/background/domains/GlobalMark.ts +++ b/src/background/domains/GlobalMark.ts @@ -1,24 +1,6 @@ -export default class GlobalMark { - constructor(tabId, url, x, y) { - this.tabId0 = tabId; - this.url0 = url; - this.x0 = x; - this.y0 = y; - } - - get tabId() { - return this.tabId0; - } - - get url() { - return this.url0; - } - - get x() { - return this.x0; - } - - get y() { - return this.y0; - } +export interface GlobalMark { + readonly tabId: number; + readonly url: string; + readonly x: number; + readonly y: number; } diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts index f691515..7ad5d24 100644 --- a/src/background/infrastructures/ConsoleClient.ts +++ b/src/background/infrastructures/ConsoleClient.ts @@ -1,34 +1,34 @@ import messages from '../../shared/messages'; export default class ConsoleClient { - showCommand(tabId, command) { + showCommand(tabId: number, command: string): Promise { return browser.tabs.sendMessage(tabId, { type: messages.CONSOLE_SHOW_COMMAND, command, }); } - showFind(tabId) { + showFind(tabId: number): Promise { return browser.tabs.sendMessage(tabId, { type: messages.CONSOLE_SHOW_FIND }); } - showInfo(tabId, message) { + showInfo(tabId: number, message: string): Promise { return browser.tabs.sendMessage(tabId, { type: messages.CONSOLE_SHOW_INFO, text: message, }); } - showError(tabId, message) { + showError(tabId: number, message: string): Promise { return browser.tabs.sendMessage(tabId, { type: messages.CONSOLE_SHOW_ERROR, text: message, }); } - hide(tabId) { + hide(tabId: number): Promise { return browser.tabs.sendMessage(tabId, { type: messages.CONSOLE_HIDE, }); diff --git a/src/background/infrastructures/ContentMessageClient.ts b/src/background/infrastructures/ContentMessageClient.ts index 0fab5a3..20057c7 100644 --- a/src/background/infrastructures/ContentMessageClient.ts +++ b/src/background/infrastructures/ContentMessageClient.ts @@ -1,10 +1,10 @@ import messages from '../../shared/messages'; export default class ContentMessageClient { - async broadcastSettingsChanged() { + async broadcastSettingsChanged(): Promise { let tabs = await browser.tabs.query({}); for (let tab of tabs) { - if (tab.url.startsWith('about:')) { + if (!tab.id || tab.url && tab.url.startsWith('about:')) { continue; } browser.tabs.sendMessage(tab.id, { @@ -13,20 +13,20 @@ export default class ContentMessageClient { } } - async getAddonEnabled(tabId) { + async getAddonEnabled(tabId: number): Promise { let { enabled } = await browser.tabs.sendMessage(tabId, { type: messages.ADDON_ENABLED_QUERY, - }); + }) as { enabled: boolean }; return enabled; } - toggleAddonEnabled(tabId) { + toggleAddonEnabled(tabId: number): Promise { return browser.tabs.sendMessage(tabId, { type: messages.ADDON_TOGGLE_ENABLED, }); } - scrollTo(tabId, x, y) { + scrollTo(tabId: number, x: number, y: number): Promise { return browser.tabs.sendMessage(tabId, { type: messages.TAB_SCROLL_TO, x, diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index 5b0f62e..81d3232 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -1,4 +1,5 @@ import messages from '../../shared/messages'; +import CompletionGroup from '../domains/CompletionGroup'; import CommandController from '../controllers/CommandController'; import SettingController from '../controllers/SettingController'; import FindController from '../controllers/FindController'; @@ -8,6 +9,22 @@ import OperationController from '../controllers/OperationController'; import MarkController from '../controllers/MarkController'; export default class ContentMessageListener { + private settingController: SettingController; + + private commandController: CommandController; + + private findController: FindController; + + private addonEnabledController: AddonEnabledController; + + private linkController: LinkController; + + private backgroundOperationController: OperationController; + + private markController: MarkController; + + private consolePorts: {[tabId: number]: browser.runtime.Port}; + constructor() { this.settingController = new SettingController(); this.commandController = new CommandController(); @@ -20,20 +37,28 @@ export default class ContentMessageListener { this.consolePorts = {}; } - run() { - browser.runtime.onMessage.addListener((message, sender) => { + run(): void { + browser.runtime.onMessage.addListener(( + message: any, sender: browser.runtime.MessageSender, + ) => { try { - let ret = this.onMessage(message, sender); + let ret = this.onMessage(message, sender.tab as browser.tabs.Tab); if (!(ret instanceof Promise)) { return {}; } return ret.catch((e) => { + if (!sender.tab || !sender.tab.id) { + return; + } return browser.tabs.sendMessage(sender.tab.id, { type: messages.CONSOLE_SHOW_ERROR, text: e.message, }); }); } catch (e) { + if (!sender.tab || !sender.tab.id) { + return; + } return browser.tabs.sendMessage(sender.tab.id, { type: messages.CONSOLE_SHOW_ERROR, text: e.message, @@ -43,7 +68,7 @@ export default class ContentMessageListener { browser.runtime.onConnect.addListener(this.onConnected.bind(this)); } - onMessage(message, sender) { + onMessage(message: any, senderTab: browser.tabs.Tab): Promise | any { switch (message.type) { case messages.CONSOLE_QUERY_COMPLETIONS: return this.onConsoleQueryCompletions(message.text); @@ -59,7 +84,10 @@ export default class ContentMessageListener { return this.onAddonEnabledResponse(message.enabled); case messages.OPEN_URL: return this.onOpenUrl( - message.newTab, message.url, sender.tab.id, message.background); + message.newTab, + message.url, + senderTab.id as number, + message.background); case messages.BACKGROUND_OPERATION: return this.onBackgroundOperation(message.operation); case messages.MARK_SET_GLOBAL: @@ -67,56 +95,60 @@ export default class ContentMessageListener { case messages.MARK_JUMP_GLOBAL: return this.onMarkJumpGlobal(message.key); case messages.CONSOLE_FRAME_MESSAGE: - return this.onConsoleFrameMessage(sender.tab.id, message.message); + return this.onConsoleFrameMessage( + senderTab.id as number, message.message, + ); } + throw new Error('unsupported message: ' + message.type); } - async onConsoleQueryCompletions(line) { + async onConsoleQueryCompletions(line: string): Promise { let completions = await this.commandController.getCompletions(line); - return Promise.resolve(completions.serialize()); + return Promise.resolve(completions); } - onConsoleEnterCommand(text) { + onConsoleEnterCommand(text: string): Promise { return this.commandController.exec(text); } - - onSettingsQuery() { + onSettingsQuery(): Promise { return this.settingController.getSetting(); } - onFindGetKeyword() { + onFindGetKeyword(): Promise { return this.findController.getKeyword(); } - onFindSetKeyword(keyword) { + onFindSetKeyword(keyword: string): Promise { return this.findController.setKeyword(keyword); } - onAddonEnabledResponse(enabled) { + onAddonEnabledResponse(enabled: boolean): Promise { return this.addonEnabledController.indicate(enabled); } - onOpenUrl(newTab, url, openerId, background) { + onOpenUrl( + newTab: boolean, url: string, openerId: number, background: boolean, + ): Promise { if (newTab) { return this.linkController.openNewTab(url, openerId, background); } return this.linkController.openToTab(url, openerId); } - onBackgroundOperation(operation) { + onBackgroundOperation(operation: any): Promise { return this.backgroundOperationController.exec(operation); } - onMarkSetGlobal(key, x, y) { + onMarkSetGlobal(key: string, x: number, y: number): Promise { return this.markController.setGlobal(key, x, y); } - onMarkJumpGlobal(key) { + onMarkJumpGlobal(key: string): Promise { return this.markController.jumpGlobal(key); } - onConsoleFrameMessage(tabId, message) { + onConsoleFrameMessage(tabId: number, message: any): void { let port = this.consolePorts[tabId]; if (!port) { return; @@ -124,12 +156,14 @@ export default class ContentMessageListener { port.postMessage(message); } - onConnected(port) { + onConnected(port: browser.runtime.Port): void { if (port.name !== 'vimvixen-console') { return; } - let id = port.sender.tab.id; - this.consolePorts[id] = port; + if (port.sender && port.sender.tab && port.sender.tab.id) { + let id = port.sender.tab.id; + this.consolePorts[id] = port; + } } } diff --git a/src/background/infrastructures/MemoryStorage.ts b/src/background/infrastructures/MemoryStorage.ts index 3a7e4f2..baf9ffa 100644 --- a/src/background/infrastructures/MemoryStorage.ts +++ b/src/background/infrastructures/MemoryStorage.ts @@ -1,7 +1,7 @@ -const db = {}; +const db: {[key: string]: any} = {}; export default class MemoryStorage { - set(name, value) { + set(name: string, value: any): void { let data = JSON.stringify(value); if (typeof data === 'undefined') { throw new Error('value is not serializable'); @@ -9,7 +9,7 @@ export default class MemoryStorage { db[name] = data; } - get(name) { + get(name: string): any { let data = db[name]; if (!data) { return undefined; diff --git a/src/background/presenters/IndicatorPresenter.ts b/src/background/presenters/IndicatorPresenter.ts index 5737519..d9a615a 100644 --- a/src/background/presenters/IndicatorPresenter.ts +++ b/src/background/presenters/IndicatorPresenter.ts @@ -1,12 +1,12 @@ export default class IndicatorPresenter { - indicate(enabled) { + indicate(enabled: boolean): Promise { let path = enabled ? 'resources/enabled_32x32.png' : 'resources/disabled_32x32.png'; return browser.browserAction.setIcon({ path }); } - onClick(listener) { + onClick(listener: (arg: browser.tabs.Tab) => void): void { browser.browserAction.onClicked.addListener(listener); } } diff --git a/src/background/presenters/NotifyPresenter.ts b/src/background/presenters/NotifyPresenter.ts index a81f227..c83c205 100644 --- a/src/background/presenters/NotifyPresenter.ts +++ b/src/background/presenters/NotifyPresenter.ts @@ -1,8 +1,12 @@ const NOTIFICATION_ID = 'vimvixen-update'; export default class NotifyPresenter { - notify(title, message, onclick) { - const listener = (id) => { + notify( + title: string, + message: string, + onclick: () => void, + ): Promise { + const listener = (id: string) => { if (id !== NOTIFICATION_ID) { return; } diff --git a/src/background/presenters/TabPresenter.ts b/src/background/presenters/TabPresenter.ts index 744be39..33c6513 100644 --- a/src/background/presenters/TabPresenter.ts +++ b/src/background/presenters/TabPresenter.ts @@ -3,27 +3,29 @@ import MemoryStorage from '../infrastructures/MemoryStorage'; const CURRENT_SELECTED_KEY = 'tabs.current.selected'; const LAST_SELECTED_KEY = 'tabs.last.selected'; +type Tab = browser.tabs.Tab; + export default class TabPresenter { - open(url, tabId) { + open(url: string, tabId?: number): Promise { return browser.tabs.update(tabId, { url }); } - create(url, opts) { + create(url: string, opts?: object): Promise { return browser.tabs.create({ url, ...opts }); } - async getCurrent() { + async getCurrent(): Promise { let tabs = await browser.tabs.query({ active: true, currentWindow: true }); return tabs[0]; } - getAll() { + getAll(): Promise { return browser.tabs.query({ currentWindow: true }); } - async getLastSelectedId() { + async getLastSelectedId(): Promise { let cache = new MemoryStorage(); let tabId = await cache.get(LAST_SELECTED_KEY); if (tabId === null || typeof tabId === 'undefined') { @@ -32,25 +34,25 @@ export default class TabPresenter { return tabId; } - async getByKeyword(keyword, excludePinned = false) { + async getByKeyword(keyword: string, excludePinned = false): Promise { let tabs = await browser.tabs.query({ currentWindow: true }); return tabs.filter((t) => { - return t.url.toLowerCase().includes(keyword.toLowerCase()) || + return t.url && t.url.toLowerCase().includes(keyword.toLowerCase()) || t.title && t.title.toLowerCase().includes(keyword.toLowerCase()); }).filter((t) => { return !(excludePinned && t.pinned); }); } - select(tabId) { + select(tabId: number): Promise { return browser.tabs.update(tabId, { active: true }); } - remove(ids) { + remove(ids: number[]): Promise { return browser.tabs.remove(ids); } - async reopen() { + async reopen(): Promise { let window = await browser.windows.getCurrent(); let sessions = await browser.sessions.getRecentlyClosed(); let session = sessions.find((s) => { @@ -59,39 +61,43 @@ export default class TabPresenter { if (!session) { return; } - if (session.tab) { + if (session.tab && session.tab.sessionId) { return browser.sessions.restore(session.tab.sessionId); } - return browser.sessions.restore(session.window.sessionId); + if (session.window && session.window.sessionId) { + return browser.sessions.restore(session.window.sessionId); + } } - reload(tabId, cache) { + reload(tabId: number, cache: boolean): Promise { return browser.tabs.reload(tabId, { bypassCache: cache }); } - setPinned(tabId, pinned) { + setPinned(tabId: number, pinned: boolean): Promise { return browser.tabs.update(tabId, { pinned }); } - duplicate(id) { + duplicate(id: number): Promise { return browser.tabs.duplicate(id); } - getZoom(tabId) { + getZoom(tabId: number): Promise { return browser.tabs.getZoom(tabId); } - setZoom(tabId, factor) { + setZoom(tabId: number, factor: number): Promise { return browser.tabs.setZoom(tabId, factor); } - onSelected(listener) { + onSelected( + listener: (arg: { tabId: number, windowId: number}) => void, + ): void { browser.tabs.onActivated.addListener(listener); } } let tabPresenter = new TabPresenter(); -tabPresenter.onSelected((tab) => { +tabPresenter.onSelected((tab: any) => { let cache = new MemoryStorage(); let lastId = cache.get(CURRENT_SELECTED_KEY); diff --git a/src/background/presenters/WindowPresenter.ts b/src/background/presenters/WindowPresenter.ts index a82c4a2..e04f258 100644 --- a/src/background/presenters/WindowPresenter.ts +++ b/src/background/presenters/WindowPresenter.ts @@ -1,5 +1,5 @@ export default class WindowPresenter { - create(url) { + create(url: string): Promise { return browser.windows.create({ url }); } } diff --git a/src/background/repositories/BookmarkRepository.ts b/src/background/repositories/BookmarkRepository.ts index 99f7ec4..b4da509 100644 --- a/src/background/repositories/BookmarkRepository.ts +++ b/src/background/repositories/BookmarkRepository.ts @@ -1,5 +1,7 @@ export default class BookmarkRepository { - async create(title, url) { + async create( + title: string, url: string + ): Promise { let item = await browser.bookmarks.create({ type: 'bookmark', title, diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts index a9d2c06..48c72a5 100644 --- a/src/background/repositories/BrowserSettingRepository.ts +++ b/src/background/repositories/BrowserSettingRepository.ts @@ -1,7 +1,7 @@ import * as urls from '../../shared/urls'; export default class BrowserSettingRepository { - async getHomepageUrls() { + async getHomepageUrls(): Promise { let { value } = await browser.browserSettings.homepageOverride.get({}); return value.split('|').map(urls.normalizeUrl); } diff --git a/src/background/repositories/CompletionsRepository.ts b/src/background/repositories/CompletionsRepository.ts index 1318d36..18af587 100644 --- a/src/background/repositories/CompletionsRepository.ts +++ b/src/background/repositories/CompletionsRepository.ts @@ -1,7 +1,13 @@ +type Tab = browser.tabs.Tab; +type BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; + export default class CompletionsRepository { - async queryBookmarks(keywords) { + async queryBookmarks(keywords: string): Promise { let items = await browser.bookmarks.search({ query: keywords }); return items.filter((item) => { + if (!item.url) { + return false; + } let url = undefined; try { url = new URL(item.url); @@ -12,17 +18,17 @@ export default class CompletionsRepository { }); } - queryHistories(keywords) { + queryHistories(keywords: string): Promise { return browser.history.search({ text: keywords, startTime: 0, }); } - async queryTabs(keywords, excludePinned) { + async queryTabs(keywords: string, excludePinned: boolean): Promise { let tabs = await browser.tabs.query({ currentWindow: true }); return tabs.filter((t) => { - return t.url.toLowerCase().includes(keywords.toLowerCase()) || + return t.url && t.url.toLowerCase().includes(keywords.toLowerCase()) || t.title && t.title.toLowerCase().includes(keywords.toLowerCase()); }).filter((t) => { return !(excludePinned && t.pinned); diff --git a/src/background/repositories/FindRepository.ts b/src/background/repositories/FindRepository.ts index 74ec914..bf286e6 100644 --- a/src/background/repositories/FindRepository.ts +++ b/src/background/repositories/FindRepository.ts @@ -3,15 +3,17 @@ import MemoryStorage from '../infrastructures/MemoryStorage'; const FIND_KEYWORD_KEY = 'find-keyword'; export default class FindRepository { + private cache: MemoryStorage; + constructor() { this.cache = new MemoryStorage(); } - getKeyword() { + getKeyword(): Promise { return Promise.resolve(this.cache.get(FIND_KEYWORD_KEY)); } - setKeyword(keyword) { + setKeyword(keyword: string): Promise { this.cache.set(FIND_KEYWORD_KEY, keyword); return Promise.resolve(); } diff --git a/src/background/repositories/MarkRepository.ts b/src/background/repositories/MarkRepository.ts index 282c712..69c85f6 100644 --- a/src/background/repositories/MarkRepository.ts +++ b/src/background/repositories/MarkRepository.ts @@ -4,21 +4,23 @@ import GlobalMark from '../domains/GlobalMark'; const MARK_KEY = 'mark'; export default class MarkRepository { + private cache: MemoryStorage; + constructor() { this.cache = new MemoryStorage(); } - getMark(key) { + getMark(key: string): Promise { let marks = this.getOrEmptyMarks(); let data = marks[key]; if (!data) { return Promise.resolve(undefined); } - let mark = new GlobalMark(data.tabId, data.url, data.x, data.y); + let mark = { tabId: data.tabId, url: data.url, x: data.x, y: data.y }; return Promise.resolve(mark); } - setMark(key, mark) { + setMark(key: string, mark: GlobalMark): Promise { let marks = this.getOrEmptyMarks(); marks[key] = { tabId: mark.tabId, url: mark.url, x: mark.x, y: mark.y }; this.cache.set(MARK_KEY, marks); diff --git a/src/background/repositories/PersistentSettingRepository.ts b/src/background/repositories/PersistentSettingRepository.ts index 4cab107..3f2f4a1 100644 --- a/src/background/repositories/PersistentSettingRepository.ts +++ b/src/background/repositories/PersistentSettingRepository.ts @@ -1,7 +1,7 @@ import Setting from '../domains/Setting'; export default class SettingRepository { - async load() { + async load(): Promise { let { settings } = await browser.storage.local.get('settings'); if (!settings) { return null; diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts index c4667a9..15355ba 100644 --- a/src/background/repositories/SettingRepository.ts +++ b/src/background/repositories/SettingRepository.ts @@ -3,19 +3,21 @@ import MemoryStorage from '../infrastructures/MemoryStorage'; const CACHED_SETTING_KEY = 'setting'; export default class SettingRepository { + private cache: MemoryStorage; + constructor() { this.cache = new MemoryStorage(); } - get() { + get(): Promise { return Promise.resolve(this.cache.get(CACHED_SETTING_KEY)); } - update(value) { + update(value: any): any { return this.cache.set(CACHED_SETTING_KEY, value); } - async setProperty(name, value) { + async setProperty(name: string, value: string): Promise { let current = await this.get(); current.properties[name] = value; return this.update(current); diff --git a/src/background/repositories/VersionRepository.ts b/src/background/repositories/VersionRepository.ts deleted file mode 100644 index 4c71d05..0000000 --- a/src/background/repositories/VersionRepository.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default class VersionRepository { - async get() { - let { version } = await browser.storage.local.get('version'); - return version; - } - - update(version) { - return browser.storage.local.set({ version }); - } -} diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts index bb2c347..0a6fb03 100644 --- a/src/background/usecases/AddonEnabledUseCase.ts +++ b/src/background/usecases/AddonEnabledUseCase.ts @@ -3,10 +3,20 @@ import TabPresenter from '../presenters/TabPresenter'; import ContentMessageClient from '../infrastructures/ContentMessageClient'; export default class AddonEnabledUseCase { + private indicatorPresentor: IndicatorPresenter; + + private tabPresenter: TabPresenter; + + private contentMessageClient: ContentMessageClient; + constructor() { this.indicatorPresentor = new IndicatorPresenter(); - this.indicatorPresentor.onClick(tab => this.onIndicatorClick(tab.id)); + this.indicatorPresentor.onClick((tab) => { + if (tab.id) { + this.onIndicatorClick(tab.id); + } + }); this.tabPresenter = new TabPresenter(); this.tabPresenter.onSelected(info => this.onTabSelected(info.tabId)); @@ -14,15 +24,15 @@ export default class AddonEnabledUseCase { this.contentMessageClient = new ContentMessageClient(); } - indicate(enabled) { + indicate(enabled: boolean): Promise { return this.indicatorPresentor.indicate(enabled); } - onIndicatorClick(tabId) { + onIndicatorClick(tabId: number): Promise { return this.contentMessageClient.toggleAddonEnabled(tabId); } - async onTabSelected(tabId) { + async onTabSelected(tabId: number): Promise { let enabled = await this.contentMessageClient.getAddonEnabled(tabId); return this.indicatorPresentor.indicate(enabled); } diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts index 9ec46fe..e0e3ada 100644 --- a/src/background/usecases/CommandUseCase.ts +++ b/src/background/usecases/CommandUseCase.ts @@ -6,9 +6,21 @@ import SettingRepository from '../repositories/SettingRepository'; import BookmarkRepository from '../repositories/BookmarkRepository'; import ConsoleClient from '../infrastructures/ConsoleClient'; import ContentMessageClient from '../infrastructures/ContentMessageClient'; -import * as properties from 'shared/settings/properties'; +import * as properties from '../../shared/settings/properties'; export default class CommandIndicator { + private tabPresenter: TabPresenter; + + private windowPresenter: WindowPresenter; + + private settingRepository: SettingRepository; + + private bookmarkRepository: BookmarkRepository; + + private consoleClient: ConsoleClient; + + private contentMessageClient: ContentMessageClient; + constructor() { this.tabPresenter = new TabPresenter(); this.windowPresenter = new WindowPresenter(); @@ -19,34 +31,34 @@ export default class CommandIndicator { this.contentMessageClient = new ContentMessageClient(); } - async open(keywords) { + async open(keywords: string): Promise { let url = await this.urlOrSearch(keywords); return this.tabPresenter.open(url); } - async tabopen(keywords) { + async tabopen(keywords: string): Promise { let url = await this.urlOrSearch(keywords); return this.tabPresenter.create(url); } - async winopen(keywords) { + async winopen(keywords: string): Promise { let url = await this.urlOrSearch(keywords); return this.windowPresenter.create(url); } // eslint-disable-next-line max-statements - async buffer(keywords) { + async buffer(keywords: string): Promise { if (keywords.length === 0) { return; } - if (!isNaN(keywords)) { + if (!isNaN(Number(keywords))) { let tabs = await this.tabPresenter.getAll(); let index = parseInt(keywords, 10) - 1; if (index < 0 || tabs.length <= index) { throw new RangeError(`tab ${index + 1} does not exist`); } - return this.tabPresenter.select(tabs[index].id); + return this.tabPresenter.select(tabs[index].id as number); } else if (keywords.trim() === '%') { // Select current window return; @@ -66,13 +78,13 @@ export default class CommandIndicator { } for (let tab of tabs) { if (tab.index > current.index) { - return this.tabPresenter.select(tab.id); + return this.tabPresenter.select(tab.id as number); } } - return this.tabPresenter.select(tabs[0].id); + return this.tabPresenter.select(tabs[0].id as number); } - async bdelete(force, keywords) { + async bdelete(force: boolean, keywords: string): Promise { let excludePinned = !force; let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned); if (tabs.length === 0) { @@ -80,35 +92,35 @@ export default class CommandIndicator { } else if (tabs.length > 1) { throw new Error('More than one match for ' + keywords); } - return this.tabPresenter.remove([tabs[0].id]); + return this.tabPresenter.remove([tabs[0].id as number]); } - async bdeletes(force, keywords) { + async bdeletes(force: boolean, keywords: string): Promise { let excludePinned = !force; let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned); - let ids = tabs.map(tab => tab.id); + let ids = tabs.map(tab => tab.id as number); return this.tabPresenter.remove(ids); } - async quit() { + async quit(): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.remove([tab.id]); + return this.tabPresenter.remove([tab.id as number]); } - async quitAll() { + async quitAll(): Promise { let tabs = await this.tabPresenter.getAll(); - let ids = tabs.map(tab => tab.id); + let ids = tabs.map(tab => tab.id as number); this.tabPresenter.remove(ids); } - async addbookmark(title) { + async addbookmark(title: string): Promise { let tab = await this.tabPresenter.getCurrent(); let item = await this.bookmarkRepository.create(title, tab.url); let message = 'Saved current page: ' + item.url; return this.consoleClient.showInfo(tab.id, message); } - async set(keywords) { + async set(keywords: string): Promise { if (keywords.length === 0) { return; } @@ -118,7 +130,7 @@ export default class CommandIndicator { return this.contentMessageClient.broadcastSettingsChanged(); } - async urlOrSearch(keywords) { + async urlOrSearch(keywords: string): Promise { let settings = await this.settingRepository.get(); return urls.searchUrl(keywords, settings.search); } diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts index 7dc30ac..037d6eb 100644 --- a/src/background/usecases/CompletionsUseCase.ts +++ b/src/background/usecases/CompletionsUseCase.ts @@ -1,6 +1,5 @@ -import CompletionItem from '../domains/CompletionItem'; -import CompletionGroup from '../domains/CompletionGroup'; import Completions from '../domains/Completions'; +import CompletionGroup from '../domains/CompletionGroup'; import CommandDocs from '../domains/CommandDocs'; import CompletionsRepository from '../repositories/CompletionsRepository'; import * as filters from './filters'; @@ -10,14 +9,23 @@ import * as properties from '../../shared/settings/properties'; const COMPLETION_ITEM_LIMIT = 10; +type Tab = browser.tabs.Tab; +type HistoryItem = browser.history.HistoryItem; + export default class CompletionsUseCase { + private tabPresenter: TabPresenter; + + private completionsRepository: CompletionsRepository; + + private settingRepository: SettingRepository; + constructor() { this.tabPresenter = new TabPresenter(); this.completionsRepository = new CompletionsRepository(); this.settingRepository = new SettingRepository(); } - queryConsoleCommand(prefix) { + queryConsoleCommand(prefix: string): Promise { let keys = Object.keys(CommandDocs); let items = keys .filter(name => name.startsWith(prefix)) @@ -28,16 +36,14 @@ export default class CompletionsUseCase { })); if (items.length === 0) { - return Promise.resolve(Completions.empty()); + return Promise.resolve([]); } - return Promise.resolve( - new Completions([new CompletionGroup('Console Command', items)]) - ); + return Promise.resolve([{ name: 'Console CompletionGroup', items }]); } - async queryOpen(name, keywords) { + async queryOpen(name: string, keywords: string): Promise { let settings = await this.settingRepository.get(); - let groups = []; + let groups: CompletionGroup[] = []; let complete = settings.properties.complete || properties.defaults.complete; for (let c of complete) { @@ -45,31 +51,31 @@ export default class CompletionsUseCase { // eslint-disable-next-line no-await-in-loop let engines = await this.querySearchEngineItems(name, keywords); if (engines.length > 0) { - groups.push(new CompletionGroup('Search Engines', engines)); + groups.push({ name: 'Search Engines', items: engines }); } } else if (c === 'h') { // eslint-disable-next-line no-await-in-loop let histories = await this.queryHistoryItems(name, keywords); if (histories.length > 0) { - groups.push(new CompletionGroup('History', histories)); + groups.push({ name: 'History', items: histories }); } } else if (c === 'b') { // eslint-disable-next-line no-await-in-loop let bookmarks = await this.queryBookmarkItems(name, keywords); if (bookmarks.length > 0) { - groups.push(new CompletionGroup('Bookmarks', bookmarks)); + groups.push({ name: 'Bookmarks', items: bookmarks }); } } } - return new Completions(groups); + return groups; } // eslint-disable-next-line max-statements - async queryBuffer(name, keywords) { + async queryBuffer(name: string, keywords: string): Promise { let lastId = await this.tabPresenter.getLastSelectedId(); let trimmed = keywords.trim(); - let tabs = []; - if (trimmed.length > 0 && !isNaN(trimmed)) { + let tabs: Tab[] = []; + if (trimmed.length > 0 && !isNaN(Number(trimmed))) { let all = await this.tabPresenter.getAll(); let index = parseInt(trimmed, 10) - 1; if (index >= 0 && index < all.length) { @@ -77,18 +83,18 @@ export default class CompletionsUseCase { } } else if (trimmed === '%') { let all = await this.tabPresenter.getAll(); - let tab = all.find(t => t.active); + let tab = all.find(t => t.active) as Tab; tabs = [tab]; } else if (trimmed === '#') { if (typeof lastId !== 'undefined' && lastId !== null) { let all = await this.tabPresenter.getAll(); - let tab = all.find(t => t.id === lastId); + let tab = all.find(t => t.id === lastId) as Tab; tabs = [tab]; } } else { tabs = await this.completionsRepository.queryTabs(keywords, false); } - const flag = (tab) => { + const flag = (tab: Tab) => { if (tab.active) { return '%'; } else if (tab.id === lastId) { @@ -96,87 +102,90 @@ export default class CompletionsUseCase { } return ' '; }; - let items = tabs.map(tab => new CompletionItem({ + let items = tabs.map(tab => ({ caption: tab.index + 1 + ': ' + flag(tab) + ' ' + tab.title, content: name + ' ' + tab.title, url: tab.url, - icon: tab.favIconUrl + icon: tab.favIconUrl, })); if (items.length === 0) { - return Promise.resolve(Completions.empty()); + return Promise.resolve([]); } - return new Completions([new CompletionGroup('Buffers', items)]); + return [{ name: 'Buffers', items }]; } - queryBdelete(name, keywords) { + queryBdelete(name: string, keywords: string): Promise { return this.queryTabs(name, true, keywords); } - queryBdeleteForce(name, keywords) { + queryBdeleteForce( + name: string, keywords: string, + ): Promise { return this.queryTabs(name, false, keywords); } - querySet(name, keywords) { + querySet(name: string, keywords: string): Promise { let items = Object.keys(properties.docs).map((key) => { if (properties.types[key] === 'boolean') { return [ - new CompletionItem({ + { caption: key, content: name + ' ' + key, url: 'Enable ' + properties.docs[key], - }), - new CompletionItem({ + }, { caption: 'no' + key, content: name + ' no' + key, url: 'Disable ' + properties.docs[key], - }), + } ]; } return [ - new CompletionItem({ + { caption: key, content: name + ' ' + key, url: 'Set ' + properties.docs[key], - }) + } ]; }); - items = items.reduce((acc, val) => acc.concat(val), []); - items = items.filter((item) => { + let flatten = items.reduce((acc, val) => acc.concat(val), []); + flatten = flatten.filter((item) => { return item.caption.startsWith(keywords); }); - if (items.length === 0) { - return Promise.resolve(Completions.empty()); + if (flatten.length === 0) { + return Promise.resolve([]); } return Promise.resolve( - new Completions([new CompletionGroup('Properties', items)]) + [{ name: 'Properties', items: flatten }], ); } - async queryTabs(name, excludePinned, args) { + async queryTabs( + name: string, excludePinned: boolean, args: string, + ): Promise { let tabs = await this.completionsRepository.queryTabs(args, excludePinned); - let items = tabs.map(tab => new CompletionItem({ + let items = tabs.map(tab => ({ caption: tab.title, content: name + ' ' + tab.title, url: tab.url, icon: tab.favIconUrl })); if (items.length === 0) { - return Promise.resolve(Completions.empty()); + return Promise.resolve([]); } - return new Completions([new CompletionGroup('Buffers', items)]); + return [{ name: 'Buffers', items }]; } - async querySearchEngineItems(name, keywords) { + async querySearchEngineItems(name: string, keywords: string) { let settings = await this.settingRepository.get(); let engines = Object.keys(settings.search.engines) .filter(key => key.startsWith(keywords)); - return engines.map(key => new CompletionItem({ + return engines.map(key => ({ caption: key, content: name + ' ' + key, })); } - async queryHistoryItems(name, keywords) { + async queryHistoryItems(name: string, keywords: string) { let histories = await this.completionsRepository.queryHistories(keywords); histories = [histories] .map(filters.filterBlankTitle) @@ -184,19 +193,21 @@ export default class CompletionsUseCase { .map(filters.filterByTailingSlash) .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT)) .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0] - .sort((x, y) => x.visitCount < y.visitCount) + .sort((x: HistoryItem, y: HistoryItem) => { + return Number(x.visitCount) < Number(y.visitCount); + }) .slice(0, COMPLETION_ITEM_LIMIT); - return histories.map(page => new CompletionItem({ + return histories.map(page => ({ caption: page.title, content: name + ' ' + page.url, url: page.url })); } - async queryBookmarkItems(name, keywords) { + async queryBookmarkItems(name: string, keywords: string) { let bookmarks = await this.completionsRepository.queryBookmarks(keywords); return bookmarks.slice(0, COMPLETION_ITEM_LIMIT) - .map(page => new CompletionItem({ + .map(page => ({ caption: page.title, content: name + ' ' + page.url, url: page.url diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts index e8e5d4a..60c0439 100644 --- a/src/background/usecases/ConsoleUseCase.ts +++ b/src/background/usecases/ConsoleUseCase.ts @@ -2,60 +2,64 @@ import TabPresenter from '../presenters/TabPresenter'; import ConsoleClient from '../infrastructures/ConsoleClient'; export default class ConsoleUseCase { + private tabPresenter: TabPresenter; + + private consoleClient: ConsoleClient; + constructor() { this.tabPresenter = new TabPresenter(); this.consoleClient = new ConsoleClient(); } - async showCommand() { + async showCommand(): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showCommand(tab.id, ''); + return this.consoleClient.showCommand(tab.id as number, ''); } - async showOpenCommand(alter) { + async showOpenCommand(alter: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); let command = 'open '; if (alter) { - command += tab.url; + command += tab.url || ''; } - return this.consoleClient.showCommand(tab.id, command); + return this.consoleClient.showCommand(tab.id as number, command); } - async showTabopenCommand(alter) { + async showTabopenCommand(alter: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); let command = 'tabopen '; if (alter) { - command += tab.url; + command += tab.url || ''; } - return this.consoleClient.showCommand(tab.id, command); + return this.consoleClient.showCommand(tab.id as number, command); } - async showWinopenCommand(alter) { + async showWinopenCommand(alter: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); let command = 'winopen '; if (alter) { - command += tab.url; + command += tab.url || ''; } - return this.consoleClient.showCommand(tab.id, command); + return this.consoleClient.showCommand(tab.id as number, command); } - async showBufferCommand() { + async showBufferCommand(): Promise { let tab = await this.tabPresenter.getCurrent(); let command = 'buffer '; - return this.consoleClient.showCommand(tab.id, command); + return this.consoleClient.showCommand(tab.id as number, command); } - async showAddbookmarkCommand(alter) { + async showAddbookmarkCommand(alter: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); let command = 'addbookmark '; if (alter) { - command += tab.title; + command += tab.title || ''; } - return this.consoleClient.showCommand(tab.id, command); + return this.consoleClient.showCommand(tab.id as number, command); } - async hideConsole() { + async hideConsole(): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.hide(tab.id); + return this.consoleClient.hide(tab.id as number); } } diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts index 224e4a9..d567800 100644 --- a/src/background/usecases/FindUseCase.ts +++ b/src/background/usecases/FindUseCase.ts @@ -3,22 +3,28 @@ import TabPresenter from '../presenters/TabPresenter'; import ConsoleClient from '../infrastructures/ConsoleClient'; export default class FindUseCase { + private tabPresenter: TabPresenter; + + private findRepository: FindRepository; + + private consoleClient: ConsoleClient; + constructor() { this.tabPresenter = new TabPresenter(); this.findRepository = new FindRepository(); this.consoleClient = new ConsoleClient(); } - getKeyword() { + getKeyword(): Promise { return this.findRepository.getKeyword(); } - setKeyword(keyword) { + setKeyword(keyword: string): Promise { return this.findRepository.setKeyword(keyword); } - async findStart() { + async findStart(): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showFind(tab.id); + return this.consoleClient.showFind(tab.id as number); } } diff --git a/src/background/usecases/LinkUseCase.ts b/src/background/usecases/LinkUseCase.ts index 89412c5..2f4df7b 100644 --- a/src/background/usecases/LinkUseCase.ts +++ b/src/background/usecases/LinkUseCase.ts @@ -1,17 +1,17 @@ -import SettingRepository from '../repositories/SettingRepository'; import TabPresenter from '../presenters/TabPresenter'; export default class LinkUseCase { + private tabPresenter: TabPresenter; + constructor() { - this.settingRepository = new SettingRepository(); this.tabPresenter = new TabPresenter(); } - openToTab(url, tabId) { + openToTab(url: string, tabId: number): Promise { return this.tabPresenter.open(url, tabId); } - openNewTab(url, openerId, background) { + openNewTab(url: string, openerId: number, background: boolean): Promise { return this.tabPresenter.create(url, { openerTabId: openerId, active: !background }); diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts index 39c796b..8b544aa 100644 --- a/src/background/usecases/MarkUseCase.ts +++ b/src/background/usecases/MarkUseCase.ts @@ -1,10 +1,17 @@ -import GlobalMark from '../domains/GlobalMark'; import TabPresenter from '../presenters/TabPresenter'; import MarkRepository from '../repositories/MarkRepository'; import ConsoleClient from '../infrastructures/ConsoleClient'; import ContentMessageClient from '../infrastructures/ContentMessageClient'; export default class MarkUseCase { + private tabPresenter: TabPresenter; + + private markRepository: MarkRepository; + + private consoleClient: ConsoleClient; + + private contentMessageClient: ContentMessageClient; + constructor() { this.tabPresenter = new TabPresenter(); this.markRepository = new MarkRepository(); @@ -12,18 +19,19 @@ export default class MarkUseCase { this.contentMessageClient = new ContentMessageClient(); } - async setGlobal(key, x, y) { + async setGlobal(key: string, x: number, y: number): Promise { let tab = await this.tabPresenter.getCurrent(); - let mark = new GlobalMark(tab.id, tab.url, x, y); + let mark = { tabId: tab.id, url: tab.url, x, y }; return this.markRepository.setMark(key, mark); } - async jumpGlobal(key) { + async jumpGlobal(key: string): Promise { let current = await this.tabPresenter.getCurrent(); let mark = await this.markRepository.getMark(key); if (!mark) { - return this.consoleClient.showError(current.id, 'Mark is not set'); + return this.consoleClient.showError( + current.id as number, 'Mark is not set'); } return this.contentMessageClient.scrollTo( @@ -32,7 +40,7 @@ export default class MarkUseCase { return this.tabPresenter.select(mark.tabId); }).catch(async() => { let tab = await this.tabPresenter.create(mark.url); - let mark2 = new GlobalMark(tab.id, mark.url, mark.x, mark.y); + let mark2 = { tabId: tab.id, url: mark.url, x: mark.x, y: mark.y }; return this.markRepository.setMark(key, mark2); }); } diff --git a/src/background/usecases/SettingUseCase.ts b/src/background/usecases/SettingUseCase.ts index 9e17408..b66ce02 100644 --- a/src/background/usecases/SettingUseCase.ts +++ b/src/background/usecases/SettingUseCase.ts @@ -4,16 +4,20 @@ import PersistentSettingRepository from '../repositories/PersistentSettingReposi import SettingRepository from '../repositories/SettingRepository'; export default class SettingUseCase { + private persistentSettingRepository: PersistentSettingRepository; + + private settingRepository: SettingRepository; + constructor() { this.persistentSettingRepository = new PersistentSettingRepository(); this.settingRepository = new SettingRepository(); } - get() { + get(): Promise { return this.settingRepository.get(); } - async reload() { + async reload(): Promise { let settings = await this.persistentSettingRepository.load(); if (!settings) { settings = Setting.defaultSettings(); diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts index 16b3e14..a0b52f0 100644 --- a/src/background/usecases/TabSelectUseCase.ts +++ b/src/background/usecases/TabSelectUseCase.ts @@ -1,11 +1,13 @@ import TabPresenter from '../presenters/TabPresenter'; export default class TabSelectUseCase { + private tabPresenter: TabPresenter; + constructor() { this.tabPresenter = new TabPresenter(); } - async selectPrev(count) { + async selectPrev(count: number): Promise { let tabs = await this.tabPresenter.getAll(); if (tabs.length < 2) { return; @@ -15,10 +17,10 @@ export default class TabSelectUseCase { return; } let select = (tab.index - count + tabs.length) % tabs.length; - return this.tabPresenter.select(tabs[select].id); + return this.tabPresenter.select(tabs[select].id as number); } - async selectNext(count) { + async selectNext(count: number): Promise { let tabs = await this.tabPresenter.getAll(); if (tabs.length < 2) { return; @@ -28,24 +30,24 @@ export default class TabSelectUseCase { return; } let select = (tab.index + count) % tabs.length; - return this.tabPresenter.select(tabs[select].id); + return this.tabPresenter.select(tabs[select].id as number); } - async selectFirst() { + async selectFirst(): Promise { let tabs = await this.tabPresenter.getAll(); - return this.tabPresenter.select(tabs[0].id); + return this.tabPresenter.select(tabs[0].id as number); } - async selectLast() { + async selectLast(): Promise { let tabs = await this.tabPresenter.getAll(); - return this.tabPresenter.select(tabs[tabs.length - 1].id); + return this.tabPresenter.select(tabs[tabs.length - 1].id as number); } - async selectPrevSelected() { + async selectPrevSelected(): Promise { let tabId = await this.tabPresenter.getLastSelectedId(); if (tabId === null || typeof tabId === 'undefined') { - return; + return Promise.resolve(); } - this.tabPresenter.select(tabId); + return this.tabPresenter.select(tabId); } } diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts index d930842..1615333 100644 --- a/src/background/usecases/TabUseCase.ts +++ b/src/background/usecases/TabUseCase.ts @@ -2,20 +2,24 @@ import TabPresenter from '../presenters/TabPresenter'; import BrowserSettingRepository from '../repositories/BrowserSettingRepository'; export default class TabUseCase { + private tabPresenter: TabPresenter; + + private browserSettingRepository: BrowserSettingRepository; + constructor() { this.tabPresenter = new TabPresenter(); this.browserSettingRepository = new BrowserSettingRepository(); } - async close(force) { + async close(force: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); if (!force && tab.pinned) { - return; + return Promise.resolve(); } - return this.tabPresenter.remove([tab.id]); + return this.tabPresenter.remove([tab.id as number]); } - async closeRight() { + async closeRight(): Promise { let tabs = await this.tabPresenter.getAll(); tabs.sort((t1, t2) => t1.index - t2.index); let index = tabs.findIndex(t => t.active); @@ -25,42 +29,42 @@ export default class TabUseCase { for (let i = index + 1; i < tabs.length; ++i) { let tab = tabs[i]; if (!tab.pinned) { - this.tabPresenter.remove(tab.id); + this.tabPresenter.remove([tab.id as number]); } } } - reopen() { + reopen(): Promise { return this.tabPresenter.reopen(); } - async reload(cache) { + async reload(cache: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.reload(tab.id, cache); + return this.tabPresenter.reload(tab.id as number, cache); } - async setPinned(pinned) { + async setPinned(pinned: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setPinned(tab.id, pinned); + return this.tabPresenter.setPinned(tab.id as number, pinned); } - async togglePinned() { + async togglePinned(): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setPinned(tab.id, !tab.pinned); + return this.tabPresenter.setPinned(tab.id as number, !tab.pinned); } - async duplicate() { + async duplicate(): Promise { let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.duplicate(tab.id); + return this.tabPresenter.duplicate(tab.id as number); } - async openPageSource() { + async openPageSource(): Promise { let tab = await this.tabPresenter.getCurrent(); let url = 'view-source:' + tab.url; return this.tabPresenter.create(url); } - async openHome(newTab) { + async openHome(newTab: boolean): Promise { let tab = await this.tabPresenter.getCurrent(); let urls = await this.browserSettingRepository.getHomepageUrls(); if (urls.length === 1 && urls[0] === 'about:home') { diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts index ed5112b..207f9e2 100644 --- a/src/background/usecases/VersionUseCase.ts +++ b/src/background/usecases/VersionUseCase.ts @@ -3,21 +3,25 @@ import TabPresenter from '../presenters/TabPresenter'; import NotifyPresenter from '../presenters/NotifyPresenter'; export default class VersionUseCase { + private tabPresenter: TabPresenter; + + private notifyPresenter: NotifyPresenter; + constructor() { this.tabPresenter = new TabPresenter(); this.notifyPresenter = new NotifyPresenter(); } - notify() { + notify(): Promise { let title = `Vim Vixen ${manifest.version} has been installed`; let message = 'Click here to see release notes'; let url = this.releaseNoteUrl(manifest.version); - this.notifyPresenter.notify(title, message, () => { + return this.notifyPresenter.notify(title, message, () => { this.tabPresenter.create(url); }); } - releaseNoteUrl(version) { + releaseNoteUrl(version?: string): string { if (version) { return `https://github.com/ueokande/vim-vixen/releases/tag/${version}`; } diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts index 692d6d9..661c3cd 100644 --- a/src/background/usecases/ZoomUseCase.ts +++ b/src/background/usecases/ZoomUseCase.ts @@ -1,35 +1,39 @@ import TabPresenter from '../presenters/TabPresenter'; -const ZOOM_SETTINGS = [ +const ZOOM_SETTINGS: number[] = [ 0.33, 0.50, 0.66, 0.75, 0.80, 0.90, 1.00, 1.10, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00 ]; export default class ZoomUseCase { + private tabPresenter: TabPresenter; + constructor() { this.tabPresenter = new TabPresenter(); } - async zoomIn(tabId) { + async zoomIn(): Promise { let tab = await this.tabPresenter.getCurrent(); - let current = await this.tabPresenter.getZoom(tab.id); + let tabId = tab.id as number; + let current = await this.tabPresenter.getZoom(tabId); let factor = ZOOM_SETTINGS.find(f => f > current); if (factor) { - return this.tabPresenter.setZoom(tabId, factor); + return this.tabPresenter.setZoom(tabId as number, factor); } } - async zoomOut(tabId) { + async zoomOut(): Promise { let tab = await this.tabPresenter.getCurrent(); - let current = await this.tabPresenter.getZoom(tab.id); - let factor = [].concat(ZOOM_SETTINGS).reverse().find(f => f < current); + let tabId = tab.id as number; + let current = await this.tabPresenter.getZoom(tabId); + let factor = ZOOM_SETTINGS.slice(0).reverse().find(f => f < current); if (factor) { - return this.tabPresenter.setZoom(tabId, factor); + return this.tabPresenter.setZoom(tabId as number, factor); } } - zoomNutoral(tabId) { - return this.tabPresenter.setZoom(tabId, 1); + async zoomNutoral(): Promise { + let tab = await this.tabPresenter.getCurrent(); + return this.tabPresenter.setZoom(tab.id as number, 1); } - } diff --git a/src/background/usecases/filters.ts b/src/background/usecases/filters.ts index d057dca..44eb56f 100644 --- a/src/background/usecases/filters.ts +++ b/src/background/usecases/filters.ts @@ -1,40 +1,42 @@ -const filterHttp = (items) => { - let httpsHosts = items.map(x => new URL(x.url)) +type Item = browser.history.HistoryItem; + +const filterHttp = (items: Item[]): Item[] => { + let httpsHosts = items.map(x => new URL(x.url as string)) .filter(x => x.protocol === 'https:') .map(x => x.host); - httpsHosts = new Set(httpsHosts); + let hostsSet = new Set(httpsHosts); - return items.filter((item) => { - let url = new URL(item.url); - return url.protocol === 'https:' || !httpsHosts.has(url.host); + return items.filter((item: Item) => { + let url = new URL(item.url as string); + return url.protocol === 'https:' || !hostsSet.has(url.host); }); }; -const filterBlankTitle = (items) => { +const filterBlankTitle = (items: Item[]): Item[] => { return items.filter(item => item.title && item.title !== ''); }; -const filterByTailingSlash = (items) => { - let urls = items.map(item => new URL(item.url)); +const filterByTailingSlash = (items: Item[]): Item[] => { + let urls = items.map(item => new URL(item.url as string)); let simplePaths = urls .filter(url => url.hash === '' && url.search === '') .map(url => url.origin + url.pathname); - simplePaths = new Set(simplePaths); + let pathsSet = new Set(simplePaths); return items.filter((item) => { - let url = new URL(item.url); + let url = new URL(item.url as string); if (url.hash !== '' || url.search !== '' || url.pathname.slice(-1) !== '/') { return true; } - return !simplePaths.has(url.origin + url.pathname.slice(0, -1)); + return !pathsSet.has(url.origin + url.pathname.slice(0, -1)); }); }; -const filterByPathname = (items, min) => { - let hash = {}; +const filterByPathname = (items: Item[], min: number): Item[] => { + let hash: {[key: string]: Item} = {}; for (let item of items) { - let url = new URL(item.url); + let url = new URL(item.url as string); let pathname = url.origin + url.pathname; if (!hash[pathname]) { hash[pathname] = item; @@ -49,10 +51,10 @@ const filterByPathname = (items, min) => { return filtered; }; -const filterByOrigin = (items, min) => { - let hash = {}; +const filterByOrigin = (items: Item[], min: number): Item[] => { + let hash: {[key: string]: Item} = {}; for (let item of items) { - let origin = new URL(item.url).origin; + let origin = new URL(item.url as string).origin; if (!hash[origin]) { hash[origin] = item; } else if (hash[origin].url.length > item.url.length) { diff --git a/src/background/usecases/parsers.ts b/src/background/usecases/parsers.ts index 43c8177..3616ac3 100644 --- a/src/background/usecases/parsers.ts +++ b/src/background/usecases/parsers.ts @@ -1,4 +1,4 @@ -const mustNumber = (v) => { +const mustNumber = (v: any): number => { let num = Number(v); if (isNaN(num)) { throw new Error('Not number: ' + v); @@ -6,8 +6,11 @@ const mustNumber = (v) => { return num; }; -const parseSetOption = (word, types) => { - let [key, value] = word.split('='); +const parseSetOption = ( + word: string, + types: { [key: string]: string }, +): any[] => { + let [key, value]: any[] = word.split('='); if (value === undefined) { value = !key.startsWith('no'); key = value ? key : key.slice(2); @@ -26,6 +29,7 @@ const parseSetOption = (word, types) => { case 'number': return [key, mustNumber(value)]; case 'boolean': return [key, value]; } + throw new Error('Unknown property type: ' + type); }; export { parseSetOption }; diff --git a/src/content/scrolls.ts b/src/content/scrolls.ts index f3124a1..bbf2491 100644 --- a/src/content/scrolls.ts +++ b/src/content/scrolls.ts @@ -90,16 +90,6 @@ class Scroller { } } -class RoughtScroller { - constructor(element) { - this.element = element; - } - - scroll(x, y) { - this.element.scrollTo(x, y); - } -} - const getScroll = () => { let target = scrollTarget(); return { x: target.scrollLeft, y: target.scrollTop }; diff --git a/test/background/domains/GlobalMark.test.ts b/test/background/domains/GlobalMark.test.ts deleted file mode 100644 index ed636e9..0000000 --- a/test/background/domains/GlobalMark.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import GlobalMark from 'background/domains/GlobalMark'; - -describe('background/domains/global-mark', () => { - describe('constructor and getter', () => { - let mark = new GlobalMark(1, 'http://example.com', 10, 30); - expect(mark.tabId).to.equal(1); - expect(mark.url).to.equal('http://example.com'); - expect(mark.x).to.equal(10); - expect(mark.y).to.equal(30); - }); -}); diff --git a/test/background/repositories/Mark.test.ts b/test/background/repositories/Mark.test.ts index 2a5b099..167e512 100644 --- a/test/background/repositories/Mark.test.ts +++ b/test/background/repositories/Mark.test.ts @@ -9,12 +9,11 @@ describe('background/repositories/mark', () => { }); it('get and set', async() => { - let mark = new GlobalMark(1, 'http://example.com', 10, 30); + let mark = { tabId: 1, url: 'http://example.com', x: 10, y: 30 }; repository.setMark('A', mark); let got = await repository.getMark('A'); - expect(got).to.be.a('object'); expect(got.tabId).to.equal(1); expect(got.url).to.equal('http://example.com'); expect(got.x).to.equal(10); diff --git a/test/background/repositories/Version.ts b/test/background/repositories/Version.ts deleted file mode 100644 index c7fa88b..0000000 --- a/test/background/repositories/Version.ts +++ /dev/null @@ -1,34 +0,0 @@ -import VersionRepository from 'background/repositories/Version'; - -describe("background/repositories/version", () => { - let versionRepository; - - beforeEach(() => { - versionRepository = new VersionRepository; - }); - - describe('#get', () => { - beforeEach(() => { - return browser.storage.local.remove('version'); - }); - - it('loads saved version', async() => { - await browser.storage.local.set({ version: '1.2.3' }); - let version = await this.versionRepository.get(); - expect(version).to.equal('1.2.3'); - }); - - it('returns undefined if no versions in storage', async() => { - let version = await storage.load(); - expect(version).to.be.a('undefined'); - }); - }); - - describe('#update', () => { - it('saves version string', async() => { - await versionRepository.update('2.3.4'); - let { version } = await browser.storage.local.get('version'); - expect(version).to.equal('2.3.4'); - }); - }); -}); -- cgit v1.2.3 From 0452370df43cc4263f268e7064f824d7e6e489b3 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 1 May 2019 23:10:37 +0900 Subject: Types on src/console --- src/background/usecases/CompletionsUseCase.ts | 12 ++-- src/console/actions/console.ts | 34 +++++----- src/console/actions/index.ts | 76 ++++++++++++++++++---- src/console/components/Console.tsx | 43 +++++++----- src/console/components/console/Completion.tsx | 45 ++++++++----- src/console/components/console/CompletionItem.tsx | 9 ++- src/console/components/console/CompletionTitle.tsx | 11 ++-- src/console/components/console/Input.tsx | 31 +++++---- src/console/components/console/Message.tsx | 13 ++-- src/console/index.tsx | 10 +-- src/console/reducers/index.ts | 23 +++++-- test/console/actions/console.test.ts | 2 +- test/console/reducers/console.test.ts | 2 +- 13 files changed, 206 insertions(+), 105 deletions(-) (limited to 'test') diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts index 037d6eb..f3a808b 100644 --- a/src/background/usecases/CompletionsUseCase.ts +++ b/src/background/usecases/CompletionsUseCase.ts @@ -1,4 +1,3 @@ -import Completions from '../domains/Completions'; import CompletionGroup from '../domains/CompletionGroup'; import CommandDocs from '../domains/CommandDocs'; import CompletionsRepository from '../repositories/CompletionsRepository'; @@ -25,7 +24,7 @@ export default class CompletionsUseCase { this.settingRepository = new SettingRepository(); } - queryConsoleCommand(prefix: string): Promise { + queryConsoleCommand(prefix: string): Promise { let keys = Object.keys(CommandDocs); let items = keys .filter(name => name.startsWith(prefix)) @@ -38,10 +37,10 @@ export default class CompletionsUseCase { if (items.length === 0) { return Promise.resolve([]); } - return Promise.resolve([{ name: 'Console CompletionGroup', items }]); + return Promise.resolve([{ name: 'Console Command', items }]); } - async queryOpen(name: string, keywords: string): Promise { + async queryOpen(name: string, keywords: string): Promise { let settings = await this.settingRepository.get(); let groups: CompletionGroup[] = []; @@ -71,7 +70,10 @@ export default class CompletionsUseCase { } // eslint-disable-next-line max-statements - async queryBuffer(name: string, keywords: string): Promise { + async queryBuffer( + name: string, + keywords: string, + ): Promise { let lastId = await this.tabPresenter.getLastSelectedId(); let trimmed = keywords.trim(); let tabs: Tab[] = []; diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts index 3713a76..ceb419c 100644 --- a/src/console/actions/console.ts +++ b/src/console/actions/console.ts @@ -1,40 +1,40 @@ -import messages from 'shared/messages'; -import actions from 'console/actions'; +import messages from '../../shared/messages'; +import * as actions from './index'; -const hide = () => { +const hide = (): actions.ConsoleAction => { return { type: actions.CONSOLE_HIDE, }; }; -const showCommand = (text) => { +const showCommand = (text: string): actions.ConsoleAction => { return { type: actions.CONSOLE_SHOW_COMMAND, text: text }; }; -const showFind = () => { +const showFind = (): actions.ConsoleAction => { return { type: actions.CONSOLE_SHOW_FIND, }; }; -const showError = (text) => { +const showError = (text: string): actions.ConsoleAction => { return { type: actions.CONSOLE_SHOW_ERROR, text: text }; }; -const showInfo = (text) => { +const showInfo = (text: string): actions.ConsoleAction => { return { type: actions.CONSOLE_SHOW_INFO, text: text }; }; -const hideCommand = () => { +const hideCommand = (): actions.ConsoleAction => { window.top.postMessage(JSON.stringify({ type: messages.CONSOLE_UNFOCUS, }), '*'); @@ -43,15 +43,17 @@ const hideCommand = () => { }; }; -const enterCommand = async(text) => { +const enterCommand = async( + text: string, +): Promise => { await browser.runtime.sendMessage({ type: messages.CONSOLE_ENTER_COMMAND, text, }); - return hideCommand(text); + return hideCommand(); }; -const enterFind = (text) => { +const enterFind = (text: string): actions.ConsoleAction => { window.top.postMessage(JSON.stringify({ type: messages.CONSOLE_ENTER_FIND, text, @@ -59,14 +61,14 @@ const enterFind = (text) => { return hideCommand(); }; -const setConsoleText = (consoleText) => { +const setConsoleText = (consoleText: string): actions.ConsoleAction => { return { type: actions.CONSOLE_SET_CONSOLE_TEXT, consoleText, }; }; -const getCompletions = async(text) => { +const getCompletions = async(text: string): Promise => { let completions = await browser.runtime.sendMessage({ type: messages.CONSOLE_QUERY_COMPLETIONS, text, @@ -78,13 +80,13 @@ const getCompletions = async(text) => { }; }; -const completionNext = () => { +const completionNext = (): actions.ConsoleAction => { return { type: actions.CONSOLE_COMPLETION_NEXT, }; }; -const completionPrev = () => { +const completionPrev = (): actions.ConsoleAction => { return { type: actions.CONSOLE_COMPLETION_PREV, }; @@ -92,5 +94,5 @@ const completionPrev = () => { export { hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText, - enterCommand, enterFind, getCompletions, completionNext, completionPrev + enterCommand, enterFind, getCompletions, completionNext, completionPrev, }; diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts index b394179..3770496 100644 --- a/src/console/actions/index.ts +++ b/src/console/actions/index.ts @@ -1,13 +1,63 @@ -export default { - // console commands - CONSOLE_HIDE: 'console.hide', - CONSOLE_SHOW_COMMAND: 'console.show.command', - CONSOLE_SHOW_ERROR: 'console.show.error', - CONSOLE_SHOW_INFO: 'console.show.info', - CONSOLE_HIDE_COMMAND: 'console.hide.command', - CONSOLE_SET_CONSOLE_TEXT: 'console.set.command', - CONSOLE_SET_COMPLETIONS: 'console.set.completions', - CONSOLE_COMPLETION_NEXT: 'console.completion.next', - CONSOLE_COMPLETION_PREV: 'console.completion.prev', - CONSOLE_SHOW_FIND: 'console.show.find', -}; +// console commands +export const CONSOLE_HIDE = 'console.hide'; +export const CONSOLE_SHOW_COMMAND = 'console.show.command'; +export const CONSOLE_SHOW_ERROR = 'console.show.error'; +export const CONSOLE_SHOW_INFO = 'console.show.info'; +export const CONSOLE_HIDE_COMMAND = 'console.hide.command'; +export const CONSOLE_SET_CONSOLE_TEXT = 'console.set.command'; +export const CONSOLE_SET_COMPLETIONS = 'console.set.completions'; +export const CONSOLE_COMPLETION_NEXT = 'console.completion.next'; +export const CONSOLE_COMPLETION_PREV = 'console.completion.prev'; +export const CONSOLE_SHOW_FIND = 'console.show.find'; + +interface HideAction { + type: typeof CONSOLE_HIDE; +} + +interface ShowCommand { + type: typeof CONSOLE_SHOW_COMMAND; + text: string; +} + +interface ShowFindAction { + type: typeof CONSOLE_SHOW_FIND; +} + +interface ShowErrorAction { + type: typeof CONSOLE_SHOW_ERROR; + text: string; +} + +interface ShowInfoAction { + type: typeof CONSOLE_SHOW_INFO; + text: string; +} + +interface HideCommandAction { + type: typeof CONSOLE_HIDE_COMMAND; +} + +interface SetConsoleTextAction { + type: typeof CONSOLE_SET_CONSOLE_TEXT; + consoleText: string; +} + +interface SetCompletionsAction { + type: typeof CONSOLE_SET_COMPLETIONS; + completions: any[]; + completionSource: string; +} + +interface CompletionNextAction { + type: typeof CONSOLE_COMPLETION_NEXT; +} + +interface CompletionPrevAction { + type: typeof CONSOLE_COMPLETION_PREV; +} + +export type ConsoleAction = + HideAction | ShowCommand | ShowFindAction | ShowErrorAction | + ShowInfoAction | HideCommandAction | SetConsoleTextAction | + SetCompletionsAction | CompletionNextAction | CompletionPrevAction; + diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx index 5427e43..09c0f50 100644 --- a/src/console/components/Console.tsx +++ b/src/console/components/Console.tsx @@ -1,7 +1,6 @@ import './console.scss'; import { connect } from 'react-redux'; import React from 'react'; -import PropTypes from 'prop-types'; import Input from './console/Input'; import Completion from './console/Completion'; import Message from './console/Message'; @@ -9,14 +8,29 @@ import * as consoleActions from '../../console/actions/console'; const COMPLETION_MAX_ITEMS = 33; -class Console extends React.Component { +interface Props { + mode?: string; + consoleText?: string; + messageText?: string; + children?: string; +} + +class Console extends React.Component { + private input: HTMLInputElement | null; + + constructor(props: Props) { + super(props); + + this.input = null; + } + onBlur() { if (this.props.mode === 'command' || this.props.mode === 'find') { return this.props.dispatch(consoleActions.hideCommand()); } } - doEnter(e) { + doEnter(e: React.KeyboardEvent) { e.stopPropagation(); e.preventDefault(); @@ -28,19 +42,19 @@ class Console extends React.Component { } } - selectNext(e) { + selectNext(e: React.KeyboardEvent) { this.props.dispatch(consoleActions.completionNext()); e.stopPropagation(); e.preventDefault(); } - selectPrev(e) { + selectPrev(e: React.KeyboardEvent) { this.props.dispatch(consoleActions.completionPrev()); e.stopPropagation(); e.preventDefault(); } - onKeyDown(e) { + onKeyDown(e: React.KeyboardEvent) { if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) { this.props.dispatch(consoleActions.hideCommand()); } @@ -81,7 +95,7 @@ class Console extends React.Component { } } - onChange(e) { + onChange(e: React.ChangeEvent) { let text = e.target.value; this.props.dispatch(consoleActions.setConsoleText(text)); if (this.props.mode === 'command') { @@ -90,7 +104,7 @@ class Console extends React.Component { } - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: Props) { if (!this.input) { return; } @@ -134,16 +148,11 @@ class Console extends React.Component { focus() { window.focus(); - this.input.focus(); + if (this.input) { + this.input.focus(); + } } } -Console.propTypes = { - mode: PropTypes.string, - consoleText: PropTypes.string, - messageText: PropTypes.string, - children: PropTypes.string, -}; - -const mapStateToProps = state => state; +const mapStateToProps = (state: any) => state; export default connect(mapStateToProps)(Console); diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx index 5477cb6..169a39c 100644 --- a/src/console/components/console/Completion.tsx +++ b/src/console/components/console/Completion.tsx @@ -1,15 +1,36 @@ import React from 'react'; -import PropTypes from 'prop-types'; import CompletionItem from './CompletionItem'; import CompletionTitle from './CompletionTitle'; -class Completion extends React.Component { - constructor() { - super(); +interface Item { + icon?: string; + caption?: string; + url?: string; +} + +interface Group { + name: string; + items: Item[]; +} + +interface Props { + select: number; + size: number; + completions: Group[]; +} + +interface State { + viewOffset: number; + select: number; +} + +class Completion extends React.Component { + constructor(props: Props) { + super(props); this.state = { viewOffset: 0, select: -1 }; } - static getDerivedStateFromProps(nextProps, prevState) { + static getDerivedStateFromProps(nextProps: Props, prevState: State) { if (prevState.select === nextProps.select) { return null; } @@ -24,6 +45,7 @@ class Completion extends React.Component { } index += g.items.length; } + return -1; })(); let viewOffset = 0; @@ -70,17 +92,4 @@ class Completion extends React.Component { } } -Completion.propTypes = { - select: PropTypes.number, - size: PropTypes.number, - completions: PropTypes.arrayOf(PropTypes.shape({ - name: PropTypes.string, - items: PropTypes.arrayOf(PropTypes.shape({ - icon: PropTypes.string, - caption: PropTypes.string, - url: PropTypes.string, - })), - })), -}; - export default Completion; diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx index 3dc552b..1cbf3de 100644 --- a/src/console/components/console/CompletionItem.tsx +++ b/src/console/components/console/CompletionItem.tsx @@ -1,7 +1,14 @@ import React from 'react'; import PropTypes from 'prop-types'; -const CompletionItem = (props) => { +interface Props { + highlight: boolean; + caption?: string; + url?: string; + icon?: string; +} + +const CompletionItem = (props: Props) => { let className = 'vimvixen-console-completion-item'; if (props.highlight) { className += ' vimvixen-completion-selected'; diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx index 4fcba3f..2543619 100644 --- a/src/console/components/console/CompletionTitle.tsx +++ b/src/console/components/console/CompletionTitle.tsx @@ -1,14 +1,13 @@ import React from 'react'; -import PropTypes from 'prop-types'; -const CompletionTitle = (props) => { +interface Props { + title: string; +} + +const CompletionTitle = (props: Props) => { return
  • {props.title}
  • ; }; -CompletionTitle.propTypes = { - title: PropTypes.string, -}; - export default CompletionTitle; diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx index cbd3348..d0348bd 100644 --- a/src/console/components/console/Input.tsx +++ b/src/console/components/console/Input.tsx @@ -1,9 +1,26 @@ import React from 'react'; -import PropTypes from 'prop-types'; -class Input extends React.Component { +interface Props { + mode: string; + value: string; + onBlur: (e: React.FocusEvent) => void; + onKeyDown: (e: React.KeyboardEvent) => void; + onChange: (e: React.ChangeEvent) => void; +} + +class Input extends React.Component { + private input: HTMLInputElement | null; + + constructor(props: Props) { + super(props); + + this.input = null; + } + focus() { - this.input.focus(); + if (this.input) { + this.input.focus(); + } } render() { @@ -32,12 +49,4 @@ class Input extends React.Component { } } -Input.propTypes = { - mode: PropTypes.string, - value: PropTypes.string, - onBlur: PropTypes.func, - onKeyDown: PropTypes.func, - onChange: PropTypes.func, -}; - export default Input; diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx index dd96248..07a929e 100644 --- a/src/console/components/console/Message.tsx +++ b/src/console/components/console/Message.tsx @@ -1,7 +1,11 @@ import React from 'react'; -import PropTypes from 'prop-types'; -const Message = (props) => { +interface Props { + mode: string; + children: string[]; +} + +const Message = (props: Props) => { switch (props.mode) { case 'error': return ( @@ -16,10 +20,7 @@ const Message = (props) => {

    ); } -}; - -Message.propTypes = { - children: PropTypes.string, + return null; }; export default Message; diff --git a/src/console/index.tsx b/src/console/index.tsx index 3190a9a..ee3a8ee 100644 --- a/src/console/index.tsx +++ b/src/console/index.tsx @@ -1,8 +1,8 @@ -import messages from 'shared/messages'; -import reducers from 'console/reducers'; +import messages from '../shared/messages'; +import reducers from './reducers'; import { createStore, applyMiddleware } from 'redux'; import promise from 'redux-promise'; -import * as consoleActions from 'console/actions/console'; +import * as consoleActions from './actions/console'; import { Provider } from 'react-redux'; import Console from './components/Console'; import React from 'react'; @@ -22,7 +22,7 @@ window.addEventListener('load', () => { wrapper); }); -const onMessage = (message) => { +const onMessage = (message: any): any => { switch (message.type) { case messages.CONSOLE_SHOW_COMMAND: return store.dispatch(consoleActions.showCommand(message.command)); @@ -38,5 +38,5 @@ const onMessage = (message) => { }; browser.runtime.onMessage.addListener(onMessage); -let port = browser.runtime.connect({ name: 'vimvixen-console' }); +let port = browser.runtime.connect(undefined, { name: 'vimvixen-console' }); port.onMessage.addListener(onMessage); diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts index 614a72f..37ed715 100644 --- a/src/console/reducers/index.ts +++ b/src/console/reducers/index.ts @@ -1,4 +1,14 @@ -import actions from 'console/actions'; +import * as actions from '../actions'; + +interface State { + mode: string; + messageText: string; + consoleText: string; + completionSource: string; + completions: any[], + select: number; + viewIndex: number; +} const defaultState = { mode: '', @@ -10,7 +20,7 @@ const defaultState = { viewIndex: 0, }; -const nextSelection = (state) => { +const nextSelection = (state: State): number => { if (state.completions.length === 0) { return -1; } @@ -27,7 +37,7 @@ const nextSelection = (state) => { return -1; }; -const prevSelection = (state) => { +const prevSelection = (state: State): number => { let length = state.completions .map(g => g.items.length) .reduce((x, y) => x + y); @@ -37,7 +47,7 @@ const prevSelection = (state) => { return state.select - 1; }; -const nextConsoleText = (completions, select, defaults) => { +const nextConsoleText = (completions: any[], select: number, defaults: any) => { if (select < 0) { return defaults; } @@ -46,7 +56,10 @@ const nextConsoleText = (completions, select, defaults) => { }; // eslint-disable-next-line max-lines-per-function -export default function reducer(state = defaultState, action = {}) { +export default function reducer( + state: State = defaultState, + action: actions.ConsoleAction, +): State { switch (action.type) { case actions.CONSOLE_HIDE: return { ...state, diff --git a/test/console/actions/console.test.ts b/test/console/actions/console.test.ts index 10cd9fe..e45d008 100644 --- a/test/console/actions/console.test.ts +++ b/test/console/actions/console.test.ts @@ -1,4 +1,4 @@ -import actions from 'console/actions'; +import * as actions from 'console/actions'; import * as consoleActions from 'console/actions/console'; describe("console actions", () => { diff --git a/test/console/reducers/console.test.ts b/test/console/reducers/console.test.ts index d5a38cf..47e7daf 100644 --- a/test/console/reducers/console.test.ts +++ b/test/console/reducers/console.test.ts @@ -1,4 +1,4 @@ -import actions from 'console/actions'; +import * as actions from 'console/actions'; import reducer from 'console/reducers'; describe("console reducer", () => { -- cgit v1.2.3 From e69497fab457df486b2a7068bdd0283505461f8b Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Thu, 2 May 2019 11:12:28 +0900 Subject: Types src/settings --- src/settings/actions/index.ts | 39 +++++++++++++++---- src/settings/actions/setting.ts | 18 ++++----- src/settings/components/form/BlacklistForm.tsx | 28 +++++++------ src/settings/components/form/KeymapsForm.tsx | 32 ++++++++------- src/settings/components/form/PropertiesForm.tsx | 32 ++++++++------- src/settings/components/form/SearchForm.tsx | 38 +++++++++--------- src/settings/components/index.tsx | 44 ++++++++++++--------- src/settings/components/ui/AddButton.tsx | 5 ++- src/settings/components/ui/DeleteButton.tsx | 5 ++- src/settings/components/ui/Input.tsx | 52 ++++++++++++++++++------- src/settings/reducers/setting.ts | 16 ++++++-- test/settings/reducers/setting.test.ts | 2 +- 12 files changed, 194 insertions(+), 117 deletions(-) (limited to 'test') diff --git a/src/settings/actions/index.ts b/src/settings/actions/index.ts index 016f2a5..75c6bb5 100644 --- a/src/settings/actions/index.ts +++ b/src/settings/actions/index.ts @@ -1,7 +1,32 @@ -export default { - // Settings - SETTING_SET_SETTINGS: 'setting.set.settings', - SETTING_SHOW_ERROR: 'setting.show.error', - SETTING_SWITCH_TO_FORM: 'setting.switch.to.form', - SETTING_SWITCH_TO_JSON: 'setting.switch.to.json', -}; +// Settings +export const SETTING_SET_SETTINGS = 'setting.set.settings'; +export const SETTING_SHOW_ERROR = 'setting.show.error'; +export const SETTING_SWITCH_TO_FORM = 'setting.switch.to.form'; +export const SETTING_SWITCH_TO_JSON = 'setting.switch.to.json'; + +interface SettingSetSettingsAcion { + type: typeof SETTING_SET_SETTINGS; + source: string; + json: string; + form: any; +} + +interface SettingShowErrorAction { + type: typeof SETTING_SHOW_ERROR; + error: string; + json: string; +} + +interface SettingSwitchToFormAction { + type: typeof SETTING_SWITCH_TO_FORM; + form: any; +} + +interface SettingSwitchToJsonAction { + type: typeof SETTING_SWITCH_TO_JSON; + json: string; +} + +export type SettingAction = + SettingSetSettingsAcion | SettingShowErrorAction | + SettingSwitchToFormAction | SettingSwitchToJsonAction; diff --git a/src/settings/actions/setting.ts b/src/settings/actions/setting.ts index db63a45..b03cd80 100644 --- a/src/settings/actions/setting.ts +++ b/src/settings/actions/setting.ts @@ -1,15 +1,15 @@ -import actions from 'settings/actions'; -import * as validator from 'shared/settings/validator'; -import * as settingsValues from 'shared/settings/values'; -import * as settingsStorage from 'shared/settings/storage'; +import * as actions from './index'; +import * as validator from '../../shared/settings/validator'; +import * as settingsValues from '../../shared/settings/values'; +import * as settingsStorage from '../../shared/settings/storage'; import keymaps from '../keymaps'; -const load = async() => { +const load = async(): Promise => { let settings = await settingsStorage.loadRaw(); return set(settings); }; -const save = async(settings) => { +const save = async(settings: any): Promise => { try { if (settings.source === 'json') { let value = JSON.parse(settings.json); @@ -26,7 +26,7 @@ const save = async(settings) => { return set(settings); }; -const switchToForm = (json) => { +const switchToForm = (json: string): actions.SettingAction => { try { validator.validate(JSON.parse(json)); let form = settingsValues.formFromJson(json, keymaps.allowedOps); @@ -43,7 +43,7 @@ const switchToForm = (json) => { } }; -const switchToJson = (form) => { +const switchToJson = (form: any): actions.SettingAction => { let json = settingsValues.jsonFromForm(form); return { type: actions.SETTING_SWITCH_TO_JSON, @@ -51,7 +51,7 @@ const switchToJson = (form) => { }; }; -const set = (settings) => { +const set = (settings: any): actions.SettingAction => { return { type: actions.SETTING_SET_SETTINGS, source: settings.source, diff --git a/src/settings/components/form/BlacklistForm.tsx b/src/settings/components/form/BlacklistForm.tsx index c470758..637bc1e 100644 --- a/src/settings/components/form/BlacklistForm.tsx +++ b/src/settings/components/form/BlacklistForm.tsx @@ -2,9 +2,19 @@ import './BlacklistForm.scss'; import AddButton from '../ui/AddButton'; import DeleteButton from '../ui/DeleteButton'; import React from 'react'; -import PropTypes from 'prop-types'; -class BlacklistForm extends React.Component { +interface Props { + value: string[]; + onChange: (value: string[]) => void; + onBlur: () => void; +} + +class BlacklistForm extends React.Component { + public static defaultProps: Props = { + value: [], + onChange: () => {}, + onBlur: () => {}, + }; render() { return
    @@ -28,7 +38,7 @@ class BlacklistForm extends React.Component {
    ; } - bindValue(e) { + bindValue(e: any) { let name = e.target.name; let index = e.target.getAttribute('data-index'); let next = this.props.value ? this.props.value.slice() : []; @@ -48,16 +58,4 @@ class BlacklistForm extends React.Component { } } -BlacklistForm.propTypes = { - value: PropTypes.arrayOf(PropTypes.string), - onChange: PropTypes.func, - onBlur: PropTypes.func, -}; - -BlacklistForm.defaultProps = { - value: [], - onChange: () => {}, - onBlur: () => {}, -}; - export default BlacklistForm; diff --git a/src/settings/components/form/KeymapsForm.tsx b/src/settings/components/form/KeymapsForm.tsx index 01acf61..ab44464 100644 --- a/src/settings/components/form/KeymapsForm.tsx +++ b/src/settings/components/form/KeymapsForm.tsx @@ -1,10 +1,22 @@ import './KeymapsForm.scss'; import React from 'react'; -import PropTypes from 'prop-types'; import Input from '../ui/Input'; import keymaps from '../../keymaps'; -class KeymapsForm extends React.Component { +type Value = {[key: string]: string}; + +interface Props{ + value: Value; + onChange: (e: Value) => void; + onBlur: () => void; +} + +class KeymapsForm extends React.Component { + public static defaultProps: Props = { + value: {}, + onChange: () => {}, + onBlur: () => {}, + } render() { return
    @@ -19,7 +31,7 @@ class KeymapsForm extends React.Component { return ; }) @@ -30,22 +42,12 @@ class KeymapsForm extends React.Component {
    ; } - bindValue(e) { + bindValue(name: string, value: string) { let next = { ...this.props.value }; - next[e.target.name] = e.target.value; + next[name] = value; this.props.onChange(next); } } -KeymapsForm.propTypes = { - value: PropTypes.objectOf(PropTypes.string), - onChange: PropTypes.func, -}; - -KeymapsForm.defaultProps = { - value: {}, - onChange: () => {}, -}; - export default KeymapsForm; diff --git a/src/settings/components/form/PropertiesForm.tsx b/src/settings/components/form/PropertiesForm.tsx index 979fdd8..0be5f5c 100644 --- a/src/settings/components/form/PropertiesForm.tsx +++ b/src/settings/components/form/PropertiesForm.tsx @@ -1,8 +1,20 @@ import './PropertiesForm.scss'; import React from 'react'; -import PropTypes from 'prop-types'; -class PropertiesForm extends React.Component { +interface Props { + types: {[key: string]: string}; + value: {[key: string]: any}; + onChange: (value: any) => void; + onBlur: () => void; +} + +class PropertiesForm extends React.Component { + public static defaultProps: Props = { + types: {}, + value: {}, + onChange: () => {}, + onBlur: () => {}, + }; render() { let types = this.props.types; @@ -12,13 +24,15 @@ class PropertiesForm extends React.Component { { Object.keys(types).map((name) => { let type = types[name]; - let inputType = null; + let inputType = ''; if (type === 'string') { inputType = 'text'; } else if (type === 'number') { inputType = 'number'; } else if (type === 'boolean') { inputType = 'checkbox'; + } else { + return null; } return
    ; } - bindValue(e) { + bindValue(e: React.ChangeEvent) { let name = e.target.name; let next = { ...this.props.value }; if (e.target.type.toLowerCase() === 'checkbox') { @@ -52,14 +66,4 @@ class PropertiesForm extends React.Component { } } -PropertiesForm.propTypes = { - value: PropTypes.objectOf(PropTypes.any), - onChange: PropTypes.func, -}; - -PropertiesForm.defaultProps = { - value: {}, - onChange: () => {}, -}; - export default PropertiesForm; diff --git a/src/settings/components/form/SearchForm.tsx b/src/settings/components/form/SearchForm.tsx index 6b0bd01..737e291 100644 --- a/src/settings/components/form/SearchForm.tsx +++ b/src/settings/components/form/SearchForm.tsx @@ -1,10 +1,25 @@ import './SearchForm.scss'; import React from 'react'; -import PropTypes from 'prop-types'; import AddButton from '../ui/AddButton'; import DeleteButton from '../ui/DeleteButton'; -class SearchForm extends React.Component { +interface Value { + default: string; + engines: string[][]; +} + +interface Props { + value: Value; + onChange: (value: Value) => void; + onBlur: () => void; +} + +class SearchForm extends React.Component { + public static defaultProps: Props = { + value: { default: '', engines: []}, + onChange: () => {}, + onBlur: () => {}, + } render() { let value = this.props.value; @@ -47,11 +62,11 @@ class SearchForm extends React.Component { ; } - bindValue(e) { + bindValue(e: any) { let value = this.props.value; let name = e.target.name; - let index = e.target.getAttribute('data-index'); - let next = { + let index = Number(e.target.getAttribute('data-index')); + let next: Value = { default: value.default, engines: value.engines ? value.engines.slice() : [], }; @@ -76,17 +91,4 @@ class SearchForm extends React.Component { } } -SearchForm.propTypes = { - value: PropTypes.shape({ - default: PropTypes.string, - engines: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), - }), - onChange: PropTypes.func, -}; - -SearchForm.defaultProps = { - value: { default: '', engines: []}, - onChange: () => {}, -}; - export default SearchForm; diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index 4ef59d7..f56e93f 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -6,19 +6,29 @@ import SearchForm from './form/SearchForm'; import KeymapsForm from './form/KeymapsForm'; import BlacklistForm from './form/BlacklistForm'; import PropertiesForm from './form/PropertiesForm'; -import * as properties from 'shared/settings/properties'; -import * as settingActions from 'settings/actions/setting'; +import * as properties from '../../shared/settings/properties'; +import * as settingActions from '../../settings/actions/setting'; const DO_YOU_WANT_TO_CONTINUE = 'Some settings in JSON can be lost when migrating. ' + 'Do you want to continue?'; -class SettingsComponent extends React.Component { +interface Props { + source: string; + json: string; + form: any; + error: string; + + // FIXME + store: any; +} + +class SettingsComponent extends React.Component { componentDidMount() { this.props.dispatch(settingActions.load()); } - renderFormFields(form) { + renderFormFields(form: any) { return
    Keybindings @@ -56,15 +66,15 @@ class SettingsComponent extends React.Component {
    ; } - renderJsonFields(json, error) { + renderJsonFields(json: string, error: string) { return
    @@ -90,7 +100,7 @@ class SettingsComponent extends React.Component { label='Use form' checked={this.props.source === 'form'} value='form' - onChange={this.bindSource.bind(this)} + onValueChange={this.bindSource.bind(this)} disabled={disabled} /> { fields } @@ -107,7 +117,7 @@ class SettingsComponent extends React.Component { ); } - bindForm(name, value) { + bindForm(name: string, value: any) { let settings = { source: this.props.source, json: this.props.json, @@ -117,22 +127,20 @@ class SettingsComponent extends React.Component { this.props.dispatch(settingActions.set(settings)); } - bindJson(e) { + bindJson(_name: string, value: string) { let settings = { source: this.props.source, - json: e.target.value, + json: value, form: this.props.form, }; this.props.dispatch(settingActions.set(settings)); } - bindSource(e) { + bindSource(_name: string, value: string) { let from = this.props.source; - let to = e.target.value; - - if (from === 'form' && to === 'json') { + if (from === 'form' && value === 'json') { this.props.dispatch(settingActions.switchToJson(this.props.form)); - } else if (from === 'json' && to === 'form') { + } else if (from === 'json' && value === 'form') { let b = window.confirm(DO_YOU_WANT_TO_CONTINUE); if (!b) { this.forceUpdate(); @@ -148,6 +156,6 @@ class SettingsComponent extends React.Component { } } -const mapStateToProps = state => state; +const mapStateToProps = (state: any) => state; export default connect(mapStateToProps)(SettingsComponent); diff --git a/src/settings/components/ui/AddButton.tsx b/src/settings/components/ui/AddButton.tsx index 185a03b..0577068 100644 --- a/src/settings/components/ui/AddButton.tsx +++ b/src/settings/components/ui/AddButton.tsx @@ -1,7 +1,10 @@ import './AddButton.scss'; import React from 'react'; -class AddButton extends React.Component { +interface Props extends React.AllHTMLAttributes { +} + +class AddButton extends React.Component { render() { return { +} + +class DeleteButton extends React.Component { render() { return { + name: string; + type: string; + error?: string; + label: string; + value: string; + onValueChange?: (name: string, value: string) => void; + onBlur?: (e: React.FocusEvent) => void; +} - renderText(props) { +class Input extends React.Component { + renderText(props: Props) { let inputClassName = props.error ? 'input-error' : ''; + let pp = { ...props }; + delete pp.onValueChange; return
    - +
    ; } - renderRadio(props) { + renderRadio(props: Props) { let inputClassName = props.error ? 'input-error' : ''; + let pp = { ...props }; + delete pp.onValueChange; return
    ; } - renderTextArea(props) { + renderTextArea(props: Props) { let inputClassName = props.error ? 'input-error' : ''; + let pp = { ...props }; + delete pp.onValueChange; return
    -