mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-13 21:02:08 +08:00
test(e2e): add tests for navigating Menu with keyboard (#47791)
This commit is contained in:
parent
12828fa497
commit
7f1b136e40
@ -11,6 +11,8 @@ const selectors = {
|
||||
'navigation-list': '.nav-list',
|
||||
'toggle-button': '.toggle-button-nav',
|
||||
'language-menu': '.nav-lang-menu',
|
||||
'exit-lang-menu': "[data-value='exit-lang-menu']",
|
||||
'lang-menu-option': 'button.nav-lang-menu-option',
|
||||
'sign-in-button': "[data-test-label='landing-small-cta']",
|
||||
'avatar-link': '.avatar-nav-link',
|
||||
'avatar-container': '.avatar-container'
|
||||
@ -41,10 +43,18 @@ describe('Default Navigation Menu', () => {
|
||||
testLink('News');
|
||||
testLink('Radio');
|
||||
});
|
||||
|
||||
it('should close the menu and focus on the Menu button when the Esc key is pressed while the navigation menu is expanded and an item in the menu is focused', () => {
|
||||
cy.get(selectors['navigation-list']).contains('Curriculum').focus();
|
||||
cy.focused().type('{esc}');
|
||||
cy.get(selectors['navigation-list']).should('not.be.visible');
|
||||
cy.get(selectors['toggle-button']).should('be.focused');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Language menu', () => {
|
||||
it('should render all used languages.', () => {
|
||||
cy.get(selectors['toggle-button']).should('be.visible').click();
|
||||
cy.get(selectors['navigation-list']).contains('Change Language').click();
|
||||
testAllLanguages();
|
||||
cy.get(selectors['language-menu'])
|
||||
@ -64,6 +74,86 @@ describe('Language menu', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Language menu keyboard accessibility', () => {
|
||||
before(() => {
|
||||
cy.get(selectors['exit-lang-menu']).click();
|
||||
cy.get(selectors['navigation-list']).contains('Change Language').blur();
|
||||
});
|
||||
|
||||
const langMenuOptionSelector =
|
||||
selectors['language-menu'] + ' ' + selectors['lang-menu-option'];
|
||||
|
||||
it('should open the language menu with the ENTER key', () => {
|
||||
cy.get(selectors['navigation-list'])
|
||||
.contains('Change Language')
|
||||
.type('{enter}');
|
||||
cy.get(selectors['language-menu']).should('be.visible');
|
||||
});
|
||||
|
||||
it('should open the language menu with the Up arrow key and place focus on the last item in the menu', () => {
|
||||
cy.get(selectors['exit-lang-menu']).click();
|
||||
cy.focused().type('{upArrow}');
|
||||
cy.get(selectors['language-menu']).should('be.visible');
|
||||
cy.get(langMenuOptionSelector).last().should('be.focused');
|
||||
});
|
||||
|
||||
it('should open the language menu with the Down arrow key and place focus on the first item in the menu', () => {
|
||||
cy.get(selectors['exit-lang-menu']).click();
|
||||
cy.focused().type('{downArrow}');
|
||||
cy.get(selectors['language-menu']).should('be.visible');
|
||||
cy.get(langMenuOptionSelector).first().should('be.focused');
|
||||
});
|
||||
|
||||
it('should be possible to move keyboard focus with the Up and Down arrow keys when the language menu is open', () => {
|
||||
navigateLanguagesWithKey('downArrow');
|
||||
navigateLanguagesWithKey('upArrow');
|
||||
});
|
||||
|
||||
it('should move focus to the last menu item when the first menu item is focused and the Up arrow key is pressed', () => {
|
||||
cy.get(langMenuOptionSelector).first().focus();
|
||||
cy.focused().type('{upArrow}');
|
||||
cy.get(langMenuOptionSelector).last().should('be.focused');
|
||||
});
|
||||
|
||||
it('should move focus to the first menu item when the last menu item is focused and the Down arrow key is pressed', () => {
|
||||
cy.get(langMenuOptionSelector).last().focus();
|
||||
cy.focused().type('{downArrow}');
|
||||
cy.get(langMenuOptionSelector).first().should('be.focused');
|
||||
});
|
||||
|
||||
it('should close the language menu and focus on the Change Language button when focus is on a language menu item and the Esc key is pressed', () => {
|
||||
cy.focused().type('{esc}');
|
||||
cy.get(selectors['language-menu']).should('not.be.visible');
|
||||
cy.get(selectors['navigation-list'])
|
||||
.contains('Change Language')
|
||||
.should('be.focused');
|
||||
});
|
||||
|
||||
it('should close the language options menu and put focus on the item above the Choose Language button when focus is on a language menu item and the Shift + Tab keys are pressed', () => {
|
||||
cy.focused().click();
|
||||
// cy.tab() doesn't accept tabindex="-1" elements as focusable
|
||||
// https://github.com/kuceb/cypress-plugin-tab/issues/18
|
||||
// It is better to use .tab() on focused language option
|
||||
// cy.focused().tab({ shift: true }); // uncomment this line when the issue is fixed
|
||||
cy.get('body').tab({ shift: true }); // remove this line when the above issue is fixed
|
||||
|
||||
cy.get(selectors['language-menu']).should('not.be.visible');
|
||||
cy.get(selectors['navigation-list'])
|
||||
.contains('Sign in to change theme.')
|
||||
.should('be.focused');
|
||||
});
|
||||
|
||||
// cy.tab() doesn't accept tabindex="-1" elements as focusable
|
||||
// https://github.com/kuceb/cypress-plugin-tab/issues/18
|
||||
// Also, doing .tab() from element other than language option doesn't yield the expected result
|
||||
it.skip('should focus on the next tabbable element when focus is on a language menu item and the Tab key is pressed', () => {
|
||||
cy.get(selectors['navigation-list']).contains('Change Language').click();
|
||||
cy.focused().tab();
|
||||
cy.get(selectors['language-menu']).should('not.be.visible');
|
||||
cy.get(selectors['sign-in-button']).should('be.focused');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Authenticated Navigation Menu', () => {
|
||||
before(() => {
|
||||
cy.clearCookies();
|
||||
@ -125,3 +215,26 @@ const testLink = (item, selector = 'navigation-list', checkParent) => {
|
||||
.should('have.attr', 'href')
|
||||
.and('contain', links[item.replaceAll(' ', '-').toLowerCase()]);
|
||||
};
|
||||
|
||||
const navigateLanguagesWithKey = direction => {
|
||||
const directions = ['downArrow', 'upArrow'];
|
||||
if (!directions.includes(direction)) {
|
||||
throw new Error(
|
||||
'Invalid direction: ' + direction + '\nMust be one of: ' + directions
|
||||
);
|
||||
}
|
||||
const availableLangNames = availableLangs.client
|
||||
.filter(lang => !hiddenLangs.includes(lang))
|
||||
.map(lang => LangNames[lang]);
|
||||
|
||||
if (direction === 'upArrow') {
|
||||
availableLangNames.reverse();
|
||||
// remove the first element, as it will be the focused language
|
||||
availableLangNames.shift();
|
||||
}
|
||||
|
||||
availableLangNames.forEach(langName => {
|
||||
cy.focused().type(`{${direction}}`);
|
||||
cy.focused().contains(langName);
|
||||
});
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
import 'cypress-plugin-stripe-elements';
|
||||
import 'cypress-plugin-tab';
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
53
package-lock.json
generated
53
package-lock.json
generated
@ -74,6 +74,7 @@
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.10.0",
|
||||
"cypress-plugin-stripe-elements": "1.0.2",
|
||||
"cypress-plugin-tab": "^1.0.5",
|
||||
"docsify-cli": "4.4.4",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
@ -15895,6 +15896,22 @@
|
||||
"algoliasearch": ">= 3.1 < 6"
|
||||
}
|
||||
},
|
||||
"node_modules/ally.js": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ally.js/-/ally.js-1.4.1.tgz",
|
||||
"integrity": "sha512-ZewdfuwP6VewtMN36QY0gmiyvBfMnmEaNwbVu2nTS6zRt069viTgkYgaDiqu6vRJ1VJCriNqV0jGMu44R8zNbA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"css.escape": "^1.5.0",
|
||||
"platform": "1.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/ally.js/node_modules/platform": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.3.tgz",
|
||||
"integrity": "sha512-VJK1SRmXBpjwsB4YOHYSturx48rLKMzHgCqDH2ZDa6ZbMS/N5huoNqyQdK5Fj/xayu3fqbXckn5SeCS1EbMDZg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/alphanum-sort": {
|
||||
"version": "1.0.2",
|
||||
"license": "MIT"
|
||||
@ -21652,6 +21669,15 @@
|
||||
"integrity": "sha512-tNXZ9BHooO8IGGmOpVRhNfGde/vmPY4D56pi4VHw1EWbfSuwCoveeqqjKDeRfPzMTD5gGYGwXdX2qO1S9O9GEg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cypress-plugin-tab": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cypress-plugin-tab/-/cypress-plugin-tab-1.0.5.tgz",
|
||||
"integrity": "sha512-QtTJcifOVwwbeMP3hsOzQOKf3EqKsLyjtg9ZAGlYDntrCRXrsQhe4ZQGIthRMRLKpnP6/tTk6G0gJ2sZUfRliQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ally.js": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress/node_modules/@types/node": {
|
||||
"version": "14.18.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.32.tgz",
|
||||
@ -66518,6 +66544,24 @@
|
||||
"@algolia/events": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"ally.js": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ally.js/-/ally.js-1.4.1.tgz",
|
||||
"integrity": "sha512-ZewdfuwP6VewtMN36QY0gmiyvBfMnmEaNwbVu2nTS6zRt069viTgkYgaDiqu6vRJ1VJCriNqV0jGMu44R8zNbA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css.escape": "^1.5.0",
|
||||
"platform": "1.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"platform": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.3.tgz",
|
||||
"integrity": "sha512-VJK1SRmXBpjwsB4YOHYSturx48rLKMzHgCqDH2ZDa6ZbMS/N5huoNqyQdK5Fj/xayu3fqbXckn5SeCS1EbMDZg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"alphanum-sort": {
|
||||
"version": "1.0.2"
|
||||
},
|
||||
@ -70797,6 +70841,15 @@
|
||||
"integrity": "sha512-tNXZ9BHooO8IGGmOpVRhNfGde/vmPY4D56pi4VHw1EWbfSuwCoveeqqjKDeRfPzMTD5gGYGwXdX2qO1S9O9GEg==",
|
||||
"dev": true
|
||||
},
|
||||
"cypress-plugin-tab": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cypress-plugin-tab/-/cypress-plugin-tab-1.0.5.tgz",
|
||||
"integrity": "sha512-QtTJcifOVwwbeMP3hsOzQOKf3EqKsLyjtg9ZAGlYDntrCRXrsQhe4ZQGIthRMRLKpnP6/tTk6G0gJ2sZUfRliQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ally.js": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"d": {
|
||||
"version": "1.0.1",
|
||||
"requires": {
|
||||
|
||||
@ -159,6 +159,7 @@
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "10.10.0",
|
||||
"cypress-plugin-stripe-elements": "1.0.2",
|
||||
"cypress-plugin-tab": "^1.0.5",
|
||||
"docsify-cli": "4.4.4",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user