Merge pull request #596 from ueokande/qa-0.23

QA 0.23
jh-changes
Shin'ya Ueoka 6 years ago committed by GitHub
commit 68673957ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      QA.md
  2. 34
      e2e/follow_properties.test.js
  3. 10099
      package-lock.json
  4. 12
      package.json
  5. 5
      src/background/usecases/CompletionsUseCase.ts
  6. 10
      src/content/usecases/FollowSlaveUseCase.ts
  7. 7
      src/settings/components/form/SearchForm.tsx
  8. 2
      src/settings/components/index.tsx
  9. 12
      src/settings/keymaps.ts
  10. 20
      src/shared/Settings.ts
  11. 4
      test/shared/Settings.test.ts

@ -20,10 +20,8 @@ The behaviors of the console are tested in [Console section](#consoles).
### Properties ### Properties
- [ ] Configure custom hint character by `:set hintchars=012345678` - [ ] Toggle smooth scroll by `:set smoothscroll` and `:set nosmoothscroll`
- [ ] Smooth scroll by `:set smoothscroll` - [ ] Configure smooth scroll by settings `"smoothscroll": true` and `"smoothscroll": false`
- [ ] Non-smooth scroll by `:set nosmoothscroll`
- [ ] Configure smooth scroll by settings `"smoothscroll": true`, `"smoothscroll": false`
### Settings ### Settings
@ -45,7 +43,6 @@ The behaviors of the console are tested in [Console section](#consoles).
##### Updating ##### Updating
- [ ] changes are updated on textarea blure when no errors - [ ] changes are updated on textarea blure when no errors
- [ ] changes are not updated on textarea blure when errors occurs
- [ ] keymap settings are applied to open tabs without reload - [ ] keymap settings are applied to open tabs without reload
- [ ] search settings are applied to open tabs without reload - [ ] search settings are applied to open tabs without reload

@ -3,6 +3,7 @@ const lanthan = require('lanthan');
const path = require('path'); const path = require('path');
const assert = require('assert'); const assert = require('assert');
const eventually = require('./eventually'); const eventually = require('./eventually');
const Console = require('./lib/Console');
const Key = lanthan.Key; const Key = lanthan.Key;
@ -114,7 +115,6 @@ describe('follow properties test', () => {
assert.equal(await hints[2].getStyle('display'), 'block'); assert.equal(await hints[2].getStyle('display'), 'block');
assert.equal(await hints[3].getStyle('display'), 'block'); assert.equal(await hints[3].getStyle('display'), 'block');
assert.equal(await hints[4].getStyle('display'), 'none'); assert.equal(await hints[4].getStyle('display'), 'none');
}); });
}); });
@ -147,4 +147,36 @@ describe('follow properties test', () => {
assert.equal(tabs[1].active, false); assert.equal(tabs[1].active, false);
}); });
}); });
it('should show hints with hintchars by settings', async () => {
let c = new Console(session);
await body.sendKeys(':');
await session.switchToFrame(0);
await c.sendKeys('set hintchars=abc', Key.Enter);
await session.switchToParentFrame();
await body.sendKeys('f');
await eventually(async() => {
let hints = await session.findElementsByCSS('.vimvixen-hint');
assert.equal(hints.length, 5);
assert.equal(await hints[0].getText(), 'A');
assert.equal(await hints[1].getText(), 'B');
assert.equal(await hints[2].getText(), 'C');
assert.equal(await hints[3].getText(), 'AA');
assert.equal(await hints[4].getText(), 'AB');
});
await body.sendKeys('a');
await eventually(async() => {
let hints = await session.findElementsByCSS('.vimvixen-hint');
assert.equal(await hints[0].getStyle('display'), 'block');
assert.equal(await hints[1].getStyle('display'), 'none');
assert.equal(await hints[2].getStyle('display'), 'none');
assert.equal(await hints[3].getStyle('display'), 'block');
assert.equal(await hints[4].getStyle('display'), 'block');
});
});
}); });

10099
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -24,16 +24,16 @@
"@types/chai": "^4.1.7", "@types/chai": "^4.1.7",
"@types/mocha": "^5.2.6", "@types/mocha": "^5.2.6",
"@types/prop-types": "^15.7.1", "@types/prop-types": "^15.7.1",
"@types/react": "^16.8.15", "@types/react": "^16.8.18",
"@types/react-dom": "^16.8.4", "@types/react-dom": "^16.8.4",
"@types/react-redux": "^7.0.8", "@types/react-redux": "^7.0.9",
"@types/redux-promise": "^0.5.28", "@types/redux-promise": "^0.5.28",
"@types/sinon": "^7.0.11", "@types/sinon": "^7.0.11",
"@typescript-eslint/eslint-plugin": "^1.9.0", "@typescript-eslint/eslint-plugin": "^1.9.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"css-loader": "^2.1.1", "css-loader": "^2.1.1",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-plugin-react": "^7.12.4", "eslint-plugin-react": "^7.13.0",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"jszip": "^3.2.1", "jszip": "^3.2.1",
"karma": "^4.1.0", "karma": "^4.1.0",
@ -62,8 +62,8 @@
"tsyringe": "^3.2.0", "tsyringe": "^3.2.0",
"typescript": "^3.4.5", "typescript": "^3.4.5",
"web-ext-types": "^3.1.0", "web-ext-types": "^3.1.0",
"webextensions-api-fake": "^0.7.4", "webextensions-api-fake": "^0.8.0",
"webpack": "^4.30.0", "webpack": "^4.32.2",
"webpack-cli": "^3.3.1" "webpack-cli": "^3.3.2"
} }
} }

@ -38,6 +38,9 @@ export default class CompletionsUseCase {
} }
async queryOpen(name: string, keywords: string): Promise<CompletionGroup[]> { async queryOpen(name: string, keywords: string): Promise<CompletionGroup[]> {
// TODO This logic contains view entities. They should be defined on
// content script
let settings = await this.settingRepository.get(); let settings = await this.settingRepository.get();
let groups: CompletionGroup[] = []; let groups: CompletionGroup[] = [];
@ -195,7 +198,7 @@ export default class CompletionsUseCase {
.map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT)) .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT))
.map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0] .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0]
.sort((x: HistoryItem, y: HistoryItem): number => { .sort((x: HistoryItem, y: HistoryItem): number => {
return Number(x.visitCount) - Number(y.visitCount); return Number(y.visitCount) - Number(x.visitCount);
}) })
.slice(0, COMPLETION_ITEM_LIMIT); .slice(0, COMPLETION_ITEM_LIMIT);
return histories.map(page => ({ return histories.map(page => ({

@ -63,16 +63,16 @@ export default class FollowSlaveUseCase {
if (hint instanceof LinkHint) { if (hint instanceof LinkHint) {
let url = hint.getLink(); let url = hint.getLink();
// ignore taget='_blank' let openNewTab = newTab;
if (!newTab && hint.getLinkTarget() === '_blank') { // Open link by background script in order to prevent a popup block
hint.click(); if (hint.getLinkTarget() === '_blank') {
return; openNewTab = true;
} }
// eslint-disable-next-line no-script-url // eslint-disable-next-line no-script-url
if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) { if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) {
return; return;
} }
await this.tabsClient.openUrl(url, newTab, background); await this.tabsClient.openUrl(url, openNewTab, background);
} else if (hint instanceof InputHint) { } else if (hint instanceof InputHint) {
hint.activate(); hint.activate();
} }

@ -54,6 +54,7 @@ class SearchForm extends React.Component<Props> {
</div>; </div>;
} }
// eslint-disable-next-line max-statements
bindValue(e: any) { bindValue(e: any) {
let value = this.props.value.toJSON(); let value = this.props.value.toJSON();
let name = e.target.name; let name = e.target.name;
@ -72,8 +73,12 @@ class SearchForm extends React.Component<Props> {
next.default = value.engines[index][0]; next.default = value.engines[index][0];
} else if (name === 'add') { } else if (name === 'add') {
next.engines.push(['', '']); next.engines.push(['', '']);
} else if (name === 'delete') { } else if (name === 'delete' && value.engines.length > 1) {
next.engines.splice(index, 1); next.engines.splice(index, 1);
if (value.engines[index][0] === value.default) {
let nextIndex = Math.min(index, next.engines.length - 1);
next.default = next.engines[nextIndex][0];
}
} }
this.props.onChange(FormSearch.valueOf(next)); this.props.onChange(FormSearch.valueOf(next));

@ -175,6 +175,7 @@ class SettingsComponent extends React.Component<Props> {
if (from === 'form' && value === 'json') { if (from === 'form' && value === 'json') {
this.props.dispatch(settingActions.switchToJson( this.props.dispatch(settingActions.switchToJson(
this.props.form as FormSettings)); this.props.form as FormSettings));
this.save();
} else if (from === 'json' && value === 'form') { } else if (from === 'json' && value === 'form') {
let b = window.confirm(DO_YOU_WANT_TO_CONTINUE); let b = window.confirm(DO_YOU_WANT_TO_CONTINUE);
if (!b) { if (!b) {
@ -183,6 +184,7 @@ class SettingsComponent extends React.Component<Props> {
} }
this.props.dispatch( this.props.dispatch(
settingActions.switchToForm(this.props.json as JSONSettings)); settingActions.switchToForm(this.props.json as JSONSettings));
this.save();
} }
} }

@ -1,3 +1,5 @@
/* eslint-disable max-len */
const fields = [ const fields = [
[ [
['scroll.vertically?{"count":1}', 'Scroll down'], ['scroll.vertically?{"count":1}', 'Scroll down'],
@ -19,8 +21,8 @@ const fields = [
['tabs.close', 'Close a tab'], ['tabs.close', 'Close a tab'],
['tabs.close.right', 'Close tabs to the right'], ['tabs.close.right', 'Close tabs to the right'],
['tabs.reopen', 'Reopen closed tab'], ['tabs.reopen', 'Reopen closed tab'],
['tabs.next?{"count":1}', 'Select next Tab'], ['tabs.next', 'Select next Tab'],
['tabs.prev?{"count":1}', 'Select prev Tab'], ['tabs.prev', 'Select prev Tab'],
['tabs.first', 'Select first tab'], ['tabs.first', 'Select first tab'],
['tabs.last', 'Select last tab'], ['tabs.last', 'Select last tab'],
['tabs.reload?{"cache":false}', 'Reload current tab'], ['tabs.reload?{"cache":false}', 'Reload current tab'],
@ -28,8 +30,8 @@ const fields = [
['tabs.pin.toggle', 'Toggle pinned state'], ['tabs.pin.toggle', 'Toggle pinned state'],
['tabs.duplicate', 'Duplicate a tab'], ['tabs.duplicate', 'Duplicate a tab'],
], [ ], [
['follow.start?{"newTab":false}', 'Follow a link'], ['follow.start?{"newTab":false,"background":false}', 'Follow a link'],
['follow.start?{"newTab":true}', 'Follow a link in new tab'], ['follow.start?{"newTab":true,"background":false}', 'Follow a link in new tab'],
['navigate.history.prev', 'Go back in histories'], ['navigate.history.prev', 'Go back in histories'],
['navigate.history.next', 'Go forward in histories'], ['navigate.history.next', 'Go forward in histories'],
['navigate.link.next', 'Open next link'], ['navigate.link.next', 'Open next link'],
@ -37,7 +39,7 @@ const fields = [
['navigate.parent', 'Go to parent directory'], ['navigate.parent', 'Go to parent directory'],
['navigate.root', 'Go to root directory'], ['navigate.root', 'Go to root directory'],
['page.source', 'Open page source'], ['page.source', 'Open page source'],
['page.home', 'Open start page to current tab'], ['page.home?{"newTab":false}', 'Open start page to current tab'],
['page.home?{"newTab":true}', 'Open start page in new tab'], ['page.home?{"newTab":true}', 'Open start page in new tab'],
['focus.input', 'Focus input'], ['focus.input', 'Focus input'],
], [ ], [

@ -101,17 +101,23 @@ export const blacklistValueOf = (o: any): string[] => {
export const valueOf = (o: any): Settings => { export const valueOf = (o: any): Settings => {
let settings = { ...DefaultSetting }; let settings = { ...DefaultSetting };
if (Object.prototype.hasOwnProperty.call(o, 'keymaps')) { for (let key of Object.keys(o)) {
switch (key) {
case 'keymaps':
settings.keymaps = keymapsValueOf(o.keymaps); settings.keymaps = keymapsValueOf(o.keymaps);
} break;
if (Object.prototype.hasOwnProperty.call(o, 'search')) { case 'search':
settings.search = searchValueOf(o.search); settings.search = searchValueOf(o.search);
} break;
if (Object.prototype.hasOwnProperty.call(o, 'properties')) { case 'properties':
settings.properties = propertiesValueOf(o.properties); settings.properties = propertiesValueOf(o.properties);
} break;
if (Object.prototype.hasOwnProperty.call(o, 'blacklist')) { case 'blacklist':
settings.blacklist = blacklistValueOf(o.blacklist); settings.blacklist = blacklistValueOf(o.blacklist);
break;
default:
throw new TypeError('unknown setting: ' + key);
}
} }
return settings; return settings;
}; };

@ -186,5 +186,9 @@ describe('Settings', () => {
expect(value.search.engines).to.be.an('object'); expect(value.search.engines).to.be.an('object');
expect(value.blacklist).to.be.empty; expect(value.blacklist).to.be.empty;
}); });
it('throws a TypeError with an unknown field', () => {
expect(() => settings.valueOf({ name: 'alice' })).to.throw(TypeError)
});
}); });
}); });