fix focus test breakage after zotero@6859614 (#3977)
- edits to zoteroPaneTest.js focus tests to expect the updated focus sequence: selected tab -> tabs menu -> sync button -> collectionTree toolbar -> collectionTree -> tags selector -> itemTree toolbar - updated tags selector keydown handling to explicitly handle all tab/shift-tab events using moveFocus. It is more readable and explicit focus handling for all components is required for programmic tab/shiftTab events dispatched in tests to actually move focus Fixes: #3975
This commit is contained in:
parent
2e8073ab9d
commit
c7c3784413
3 changed files with 73 additions and 49 deletions
|
@ -92,6 +92,7 @@ class Search extends React.PureComponent {
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDown}
|
||||||
value={this.state.immediateValue}
|
value={this.state.immediateValue}
|
||||||
|
className="search-input"
|
||||||
{...pick(this.props, p => p.startsWith('data-') || p.startsWith('aria-'))}
|
{...pick(this.props, p => p.startsWith('data-') || p.startsWith('aria-'))}
|
||||||
/>
|
/>
|
||||||
{this.state.immediateValue !== ''
|
{this.state.immediateValue !== ''
|
||||||
|
|
|
@ -414,7 +414,7 @@ var ZoteroPane = new function()
|
||||||
}
|
}
|
||||||
// If tag selector is collapsed, go to "New item" button, otherwise
|
// If tag selector is collapsed, go to "New item" button, otherwise
|
||||||
// default to focusing on tag selector
|
// default to focusing on tag selector
|
||||||
return false;
|
return tagContainer.querySelector(".tag-selector-list");
|
||||||
},
|
},
|
||||||
Escape: clearCollectionSearch
|
Escape: clearCollectionSearch
|
||||||
}
|
}
|
||||||
|
@ -432,30 +432,37 @@ var ZoteroPane = new function()
|
||||||
});
|
});
|
||||||
|
|
||||||
tagSelector.addEventListener("keydown", (e) => {
|
tagSelector.addEventListener("keydown", (e) => {
|
||||||
// Tab from the scrollable tag list or Shift-Tab from the input field focuses the first
|
let actionsMap = {
|
||||||
// non-disabled tag. If there are none, the tags are skipped
|
'search-input': {
|
||||||
if ((e.target.classList.contains("tag-selector-list") && e.key == "Tab" && !e.shiftKey)
|
Tab: () => tagSelector.querySelector('.tag-selector-actions'),
|
||||||
|| e.target.tagName == "input" && e.key == "Tab" && e.shiftKey) {
|
ShiftTab: () => {
|
||||||
let firstNonDisabledTag = document.querySelector('.tag-selector-item:not(.disabled)');
|
let firstNonDisabledTag = tagSelector.querySelector('.tag-selector-item:not(.disabled)');
|
||||||
if (firstNonDisabledTag) {
|
if (firstNonDisabledTag) {
|
||||||
firstNonDisabledTag.focus();
|
return firstNonDisabledTag;
|
||||||
|
}
|
||||||
|
return document.getElementById("collection-tree");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'tag-selector-item': {
|
||||||
|
Tab: () => tagSelector.querySelector(".search-input"),
|
||||||
|
ShiftTab: () => tagSelector.querySelector(".tag-selector-list"),
|
||||||
|
},
|
||||||
|
'tag-selector-actions': {
|
||||||
|
Tab: () => document.getElementById('zotero-tb-add'),
|
||||||
|
ShiftTab: () => tagSelector.querySelector(".search-input")
|
||||||
|
},
|
||||||
|
'tag-selector-list': {
|
||||||
|
Tab: () => {
|
||||||
|
let firstNonDisabledTag = tagSelector.querySelector('.tag-selector-item:not(.disabled)');
|
||||||
|
if (firstNonDisabledTag) {
|
||||||
|
return firstNonDisabledTag;
|
||||||
|
}
|
||||||
|
return tagSelector.querySelector(".search-input");
|
||||||
|
},
|
||||||
|
ShiftTab: () => document.getElementById("collection-tree"),
|
||||||
}
|
}
|
||||||
else if (e.target.classList.contains("tag-selector-list")) {
|
};
|
||||||
tagSelector.querySelector("input").focus();
|
moveFocus(actionsMap, e);
|
||||||
}
|
|
||||||
else {
|
|
||||||
tagSelector.querySelector(".tag-selector-list").focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
// Special treatment for tag selector button because it has no id
|
|
||||||
if (e.target.tagName == "button" && e.key == "Tab" && !e.shiftKey) {
|
|
||||||
document.getElementById('zotero-tb-add').focus();
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1495,7 +1495,15 @@ describe("ZoteroPane", function() {
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Focus Test";
|
collection.name = "Focus Test";
|
||||||
await collection.saveTx();
|
await collection.saveTx();
|
||||||
|
// Make sure there is a tag
|
||||||
|
var item = new Zotero.Item('newspaperArticle');
|
||||||
|
item.setCollections([collection.id]);
|
||||||
|
await item.setTags(["Tag"]);
|
||||||
|
await item.saveTx({
|
||||||
|
skipSelect: true
|
||||||
|
});
|
||||||
await waitForItemsLoad(win);
|
await waitForItemsLoad(win);
|
||||||
|
await zp.collectionsView.selectLibrary(userLibraryID);
|
||||||
});
|
});
|
||||||
|
|
||||||
var tab = new KeyboardEvent('keydown', {
|
var tab = new KeyboardEvent('keydown', {
|
||||||
|
@ -1519,27 +1527,38 @@ describe("ZoteroPane", function() {
|
||||||
bubbles: true
|
bubbles: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// TEMP: https://github.com/zotero/zotero/issues/3975
|
// Focus sequence for Zotero Pane
|
||||||
it.skip("should shift-tab through the toolbar to item-tree", async function () {
|
let sequence = [
|
||||||
|
"zotero-tb-search-dropmarker",
|
||||||
|
"zotero-tb-add",
|
||||||
|
"tag-selector-actions",
|
||||||
|
"search-input",
|
||||||
|
"tag-selector-item",
|
||||||
|
"tag-selector-list",
|
||||||
|
"collection-tree",
|
||||||
|
"zotero-collections-search",
|
||||||
|
"zotero-tb-collection-add",
|
||||||
|
"zotero-tb-sync",
|
||||||
|
"zotero-tb-tabs-menu"
|
||||||
|
];
|
||||||
|
it("should shift-tab across the zotero pane", async function () {
|
||||||
let searchBox = doc.getElementById('zotero-tb-search-textbox');
|
let searchBox = doc.getElementById('zotero-tb-search-textbox');
|
||||||
searchBox.focus();
|
searchBox.focus();
|
||||||
|
|
||||||
let sequence = [
|
|
||||||
"zotero-tb-search-dropmarker",
|
|
||||||
"zotero-tb-add",
|
|
||||||
"zotero-collections-search",
|
|
||||||
"zotero-tb-collection-add",
|
|
||||||
"zotero-tb-sync",
|
|
||||||
"zotero-tb-tabs-menu"
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let id of sequence) {
|
for (let id of sequence) {
|
||||||
doc.activeElement.dispatchEvent(shiftTab);
|
doc.activeElement.dispatchEvent(shiftTab);
|
||||||
// Wait for collection search to be revealed
|
// Wait for collection search to be revealed
|
||||||
if (id === "zotero-collections-search") {
|
if (id === "zotero-collections-search") {
|
||||||
await Zotero.Promise.delay(250);
|
await Zotero.Promise.delay(250);
|
||||||
}
|
}
|
||||||
assert.equal(doc.activeElement.id, id);
|
// Some elements don't have id, so use classes to verify they're focused
|
||||||
|
if (doc.activeElement.id) {
|
||||||
|
assert.equal(doc.activeElement.id, id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let clases = [...doc.activeElement.classList];
|
||||||
|
assert.include(clases, id);
|
||||||
|
}
|
||||||
// Wait for collection search to be hidden for subsequent tests
|
// Wait for collection search to be hidden for subsequent tests
|
||||||
if (id === "zotero-tb-collection-add") {
|
if (id === "zotero-tb-collection-add") {
|
||||||
await Zotero.Promise.delay(50);
|
await Zotero.Promise.delay(50);
|
||||||
|
@ -1552,26 +1571,23 @@ describe("ZoteroPane", function() {
|
||||||
assert.equal(doc.activeElement.id, "item-tree-main-default");
|
assert.equal(doc.activeElement.id, "item-tree-main-default");
|
||||||
});
|
});
|
||||||
|
|
||||||
// TEMP: https://github.com/zotero/zotero/issues/3975
|
it("should tab across the zotero pane", async function () {
|
||||||
it.skip("should tab through the toolbar to collection-tree", async function () {
|
|
||||||
win.Zotero_Tabs.moveFocus("current");
|
win.Zotero_Tabs.moveFocus("current");
|
||||||
let sequence = [
|
sequence.reverse();
|
||||||
"zotero-tb-tabs-menu",
|
|
||||||
"zotero-tb-sync",
|
|
||||||
"zotero-tb-collection-add",
|
|
||||||
"zotero-collections-search",
|
|
||||||
"zotero-tb-add",
|
|
||||||
"zotero-tb-search-dropmarker",
|
|
||||||
'zotero-tb-search-textbox',
|
|
||||||
'collection-tree',
|
|
||||||
];
|
|
||||||
for (let id of sequence) {
|
for (let id of sequence) {
|
||||||
doc.activeElement.dispatchEvent(tab);
|
doc.activeElement.dispatchEvent(tab);
|
||||||
// Wait for collection search to be revealed
|
// Wait for collection search to be revealed
|
||||||
if (id === "zotero-collections-search") {
|
if (id === "zotero-collections-search") {
|
||||||
await Zotero.Promise.delay(250);
|
await Zotero.Promise.delay(250);
|
||||||
}
|
}
|
||||||
assert.equal(doc.activeElement.id, id);
|
// Some elements don't have id, so use classes to verify they're focused
|
||||||
|
if (doc.activeElement.id) {
|
||||||
|
assert.equal(doc.activeElement.id, id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let clases = [...doc.activeElement.classList];
|
||||||
|
assert.include(clases, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue