From cb6c50f79c572a45ee35e0e1a6106eebd14a1f9d Mon Sep 17 00:00:00 2001
From: Taha <91777330+tahamukhtar20@users.noreply.github.com>
Date: Sat, 31 Aug 2024 17:33:31 +0500
Subject: [PATCH] [GSoC'24] Keyboard Shortcuts Customization, Cypress Tests
(#8343)
---
.../settings-modal/shortcut-settings.tsx | 7 +-
tests/cypress/e2e/features/shortcuts.js | 241 ++++++++++++++++++
2 files changed, 246 insertions(+), 2 deletions(-)
create mode 100644 tests/cypress/e2e/features/shortcuts.js
diff --git a/cvat-ui/src/components/header/settings-modal/shortcut-settings.tsx b/cvat-ui/src/components/header/settings-modal/shortcut-settings.tsx
index 33ad594787ad..0736e851844b 100644
--- a/cvat-ui/src/components/header/settings-modal/shortcut-settings.tsx
+++ b/cvat-ui/src/components/header/settings-modal/shortcut-settings.tsx
@@ -44,6 +44,7 @@ function ShortcutsSettingsComponent(props: Props): JSX.Element {
Modal.confirm({
title: 'Are you sure you want to restore defaults?',
okText: 'Yes',
+ className: 'cvat-shortcuts-settings-restore-modal',
cancelText: 'No',
onOk: () => {
const currentSettings = localStorage.getItem('clientSettings');
@@ -92,7 +93,9 @@ function ShortcutsSettingsComponent(props: Props): JSX.Element {
(
-
+
{item.name}
}
@@ -137,7 +140,7 @@ function ShortcutsSettingsComponent(props: Props): JSX.Element {
onChange={onSearchChange}
className='cvat-shortcuts-settings-search'
/>
-
+
diff --git a/tests/cypress/e2e/features/shortcuts.js b/tests/cypress/e2e/features/shortcuts.js
new file mode 100644
index 000000000000..f4d67e748209
--- /dev/null
+++ b/tests/cypress/e2e/features/shortcuts.js
@@ -0,0 +1,241 @@
+// Copyright (C) 2024 CVAT.ai Corporation
+//
+// SPDX-License-Identifier: MIT
+
+///
+
+context('Customizable Shortcuts', () => {
+ const taskName = 'A task with markdown';
+ const serverFiles = ['images/image_1.jpg'];
+ const createRectangleShape2Points = {
+ points: 'By 2 Points',
+ type: 'Shape',
+ labelName: 'label 1',
+ firstX: 250,
+ firstY: 350,
+ secondX: 350,
+ secondY: 450,
+ };
+ let taskID = null;
+ let jobID = null;
+
+ const task = {
+ labels: [
+ {
+ name: 'label 1',
+ attributes: [
+ {
+ name: 'attribute 1',
+ mutable: true,
+ input_type: 'checkbox',
+ default_value: 'false',
+ values: ['false'],
+ },
+ ],
+ type: 'any',
+ }, {
+ name: 'label 2',
+ attributes: [],
+ type: 'any',
+ }, {
+ name: 'label 3',
+ attributes: [],
+ type: 'any',
+ },
+ ],
+ name: taskName,
+ project_id: null,
+ source_storage: { location: 'local' },
+ target_storage: { location: 'local' },
+ };
+ const storage = {
+ server_files: serverFiles,
+ image_quality: 70,
+ use_zip_chunks: true,
+ use_cache: true,
+ sorting_method: 'lexicographical',
+ };
+
+ before(() => {
+ cy.visit('auth/login');
+ cy.login();
+ cy.get('.cvat-tasks-page').should('exist').and('be.visible');
+ cy.url().should('contain', '/tasks');
+ cy.headlessCreateTask(task, storage).then((response) => {
+ taskID = response.taskID;
+ [jobID] = response.jobIDs;
+ });
+ });
+
+ function testSearchShortcuts(search) {
+ const searchShortcuts = [
+ {
+ title: 'Save the job',
+ description: 'Send all changes of annotations to the server',
+ },
+ {
+ title: 'Switch automatic bordering',
+ description: 'Switch automatic bordering for polygons and polylines during drawing/editing',
+ },
+ ];
+ const searchItemClass = search === 'description' ? '.cvat-shortcuts-settings-item-title' : '.cvat-shortcuts-settings-item-description';
+ const randomSearchItem = search === 'description' ? 'random description shortcut' : 'random title shortcut';
+ cy.get('.cvat-shortcuts-settings-search input').focus();
+ for (const searchShortcut of searchShortcuts) {
+ cy.get('.cvat-shortcuts-settings-search input').type(search === 'description' ? searchShortcut.description : searchShortcut.title);
+ cy.get(searchItemClass).should('have.length', 1);
+ cy.get(searchItemClass).contains(search === 'description' ? searchShortcut.title : searchShortcut.description);
+ cy.get('.cvat-shortcuts-settings-search input').clear();
+ }
+ cy.get('.cvat-shortcuts-settings-search input').type(randomSearchItem);
+ cy.get(searchItemClass).should('not.exist');
+ cy.get('.cvat-shortcuts-settings-search input').clear();
+ cy.get('.cvat-shortcuts-settings-search input').blur();
+ }
+
+ function checkShortcutsMounted(label) {
+ cy.get('.cvat-shortcuts-modal-window-table').should('exist').and('be.visible');
+ for (let i = 1; i < 3; i++) {
+ cy.get('.cvat-shortcuts-modal-window-table').contains(label(i));
+ }
+ }
+
+ function registerF2(shouldExist) {
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().click();
+ cy.realPress(['F2']);
+ cy.get('.ant-modal-content').contains('Conflicting shortcuts detected');
+ cy.get(
+ shouldExist ?
+ '.ant-modal-content .ant-modal-confirm-btns .ant-btn-primary' :
+ '.ant-modal-content .ant-modal-confirm-btns .ant-btn-default',
+ ).click();
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().within(() => {
+ cy.get('.ant-select-selection-overflow-item').contains('f2').should(shouldExist ? 'exist' : 'not.exist');
+ });
+ if (shouldExist) {
+ cy.closeSettings();
+ cy.realPress(['F2']);
+ cy.get('.cvat-shortcuts-modal-window').should('exist').and('be.visible');
+ cy.realPress(['F2']);
+ }
+ }
+
+ after(() => {
+ cy.logout();
+ });
+
+ describe('Searching for a shortcut', () => {
+ it('Search a shortcut by its description', () => {
+ cy.openSettings();
+ cy.contains('Shortcuts').click();
+ cy.get('.cvat-shortcuts-settings-search input').should('exist').and('be.visible');
+ testSearchShortcuts('description');
+ });
+ it('Search a shortcut by its title', () => {
+ testSearchShortcuts('title');
+ });
+ });
+
+ describe('Registration and testing of new shortcuts', () => {
+ it('Registering a combination shortcut and testing if it works or not', () => {
+ cy.get('.cvat-shortcuts-settings-collapse').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-settings-label').first().click();
+ cy.get('.cvat-shortcuts-settings-collapse-item').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().click();
+ cy.realPress(['Control', 'Space']);
+ cy.closeSettings();
+ cy.realPress(['Control', 'Space']);
+ cy.get('.cvat-shortcuts-modal-window').should('exist').and('be.visible');
+ cy.realPress(['Control', 'Space']);
+ cy.openSettings();
+ registerF2(false);
+ registerF2(true);
+ });
+ });
+
+ describe('Saving, Clearing and Restoring to Default', () => {
+ it('Saving shortcuts and checking if they persist', () => {
+ cy.openSettings();
+ cy.saveSettings();
+ cy.reload();
+ cy.openSettings();
+ cy.contains('Shortcuts').click();
+ cy.get('.cvat-shortcuts-settings-collapse').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-settings-label').first().click();
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().within(() => {
+ cy.get('.ant-select-selection-overflow-item').contains('ctrl+space').should('exist');
+ });
+ });
+ it('Cleaning Shortcuts', () => {
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().click();
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select .ant-select-selection-item-remove').first().click();
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().within(() => {
+ cy.get('.ant-select-selection-overflow-item').contains('f1').should('not.exist');
+ });
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select .ant-select-clear').first().click();
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select').first().within(() => {
+ cy.get('.ant-select-selection-overflow-item').should('not.have.text');
+ });
+ });
+ it('Restoring Defaults', () => {
+ cy.get('.cvat-shortcuts-settings-restore').click();
+ cy.get('.cvat-shortcuts-settings-restore-modal .ant-btn-primary').click();
+ cy.get(
+ '.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select .ant-select-selection-overflow-item').first().should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select .ant-select-selection-overflow-item').first().contains('f1');
+ cy.saveSettings();
+ });
+ it('Modifying a shortcut via local storage and testing if its conflict is resolved', () => {
+ cy.window().then((window) => {
+ const { localStorage } = window;
+ const clientSettings = JSON.parse(localStorage.getItem('clientSettings'));
+ clientSettings.shortcuts.keyMap.SWITCH_SHORTCUTS.sequences = ['f2'];
+ localStorage.setItem('clientSettings', JSON.stringify(clientSettings));
+ });
+ cy.reload();
+ cy.openSettings();
+ cy.contains('Shortcuts').click();
+ cy.get('.cvat-shortcuts-settings-collapse').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-settings-label').first().click();
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select .ant-select-selection-overflow-item').first().contains('f2');
+ cy.get('.cvat-shortcuts-settings-collapse-item .cvat-shortcuts-settings-select .ant-select-selection-overflow-item').eq(1).should('not.have.text');
+ cy.get('.cvat-shortcuts-settings-restore').click();
+ cy.get('.cvat-shortcuts-settings-restore-modal .ant-btn-primary').click();
+ });
+ });
+
+ describe('Tag Annotation, Attribute Annotation and Labels', () => {
+ it('Tag Annotation Mode, Dynamic Titles and Description', () => {
+ cy.visit(`/tasks/${taskID}/jobs/${jobID}`);
+ cy.get('.cvat-canvas-container').should('exist').and('be.visible');
+ cy.createRectangle(createRectangleShape2Points);
+ cy.changeWorkspace('Tag annotation');
+ cy.get('.cvat-canvas-container').click();
+ cy.realPress(['F1']);
+ cy.get('.cvat-shortcuts-modal-window').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-modal-window .ant-pagination-item-2').click();
+ checkShortcutsMounted((i) => `Create a new tag "label ${i}"`);
+ cy.realPress(['F1']);
+ });
+ it('Attribute Annotation Mode, Dynamic Titles and Description', () => {
+ cy.changeWorkspace('Attribute annotation');
+ cy.get('.cvat-canvas-container').click();
+ cy.realPress(['F1']);
+ cy.get('.cvat-shortcuts-modal-window').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-modal-window .ant-pagination-item-3').click();
+ cy.get('.cvat-shortcuts-modal-window-table').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-modal-window-table').contains('Assign attribute value false');
+ cy.get('.cvat-shortcuts-modal-window-table').contains('Assign attribute value true');
+ cy.realPress(['F1']);
+ });
+ it('Labels, Dynamic Titles and Description', () => {
+ cy.changeWorkspace('Standard');
+ cy.get('.cvat-canvas-container').click();
+ cy.realPress(['F1']);
+ cy.get('.cvat-shortcuts-modal-window').should('exist').and('be.visible');
+ cy.get('.cvat-shortcuts-modal-window .ant-pagination-item-5').click();
+ checkShortcutsMounted((i) => `Switch label to label ${i}`);
+ cy.realPress(['F1']);
+ });
+ });
+});