Skip to content

Commit

Permalink
#2370 - "Erase" tool
Browse files Browse the repository at this point in the history
#2360 - "Select" tool

- added select and erase tools
- implemented DrawingEntitiesManager and RenderersManager which controls entities parameters changes and render
- added rootDir to tsconfig of core package
  • Loading branch information
rrodionov91 committed Sep 13, 2023
1 parent e26a020 commit 19b56df
Show file tree
Hide file tree
Showing 77 changed files with 1,844 additions and 818 deletions.
2 changes: 1 addition & 1 deletion example/src/PolymerToggler/PolymerToggler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface PolymerTogglerProps {

const PolymerToggler = ({ toggle }: PolymerTogglerProps): JSX.Element => {
return (
<label className={styles.switch} data-testid="PolymerToggler">
<label className={styles.switch} data-testid="polymer-toggler">
<input type="checkbox" onChange={(e) => toggle(e.target.checked)} />
<span className={styles.slider} />
</label>
Expand Down
2 changes: 1 addition & 1 deletion ketcher-autotests/constants/testIdConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const PEPTIDES_TAB = 'PEPTIDES_TAB';
const RNA_TAB = 'RNA_TAB';
const CHEM_TAB = 'CHEM_TAB';
const FAVORITES_TAB = 'FAVORITES_TAB';
const POLYMER_TOGGLER = 'PolymerToggler';
const POLYMER_TOGGLER = 'polymer-toggler';
const SUGAR = 'rna-builder-slot--sugar';
const BASE = 'rna-builder-slot--base';
const PHOSPHATE = 'rna-builder-slot--phosphate';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { test } from '@playwright/test';
import {
addMonomerToCanvas,
selectEraseTool,
selectSingleBondTool,
takeEditorScreenshot,
} from '@utils';
import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
import { bondTwoMonomers } from '@utils/macromolecules/polymerBond';
/* eslint-disable no-magic-numbers */

test.describe('Erase Tool', () => {
test.beforeEach(async ({ page }) => {
await page.goto('');
await turnOnMacromoleculesEditor(page);
});
test.skip('Delete monomer bonded with another monomers', async ({ page }) => {
/*
Test case: #2370 - "Erase" tool for macromolecules editor
Description: Erase Tool
*/

// Create 4 peptides on canvas
const MONOMER_NAME = 'Tza___3-thiazolylalanine';
const MONOMER_ALIAS = 'Tza';
await addMonomerToCanvas(page, MONOMER_NAME, 300, 300);
await addMonomerToCanvas(page, MONOMER_NAME, 400, 400);
await addMonomerToCanvas(page, MONOMER_NAME, 500, 500);
await addMonomerToCanvas(page, MONOMER_NAME, 500, 200);

// Get 4 peptides locators
const peptides = await page.getByText(MONOMER_ALIAS).locator('..');
const peptide1 = peptides.nth(0);
const peptide2 = peptides.nth(1);
const peptide3 = peptides.nth(2);
const peptide4 = peptides.nth(3);

// Select bond tool
await selectSingleBondTool(page);

// Create bonds between peptides
await bondTwoMonomers(page, peptide1, peptide2);
await bondTwoMonomers(page, peptide3, peptide2);
await bondTwoMonomers(page, peptide3, peptide4);

await takeEditorScreenshot(page);

await selectEraseTool(page);

// Delete peptide linked with two other peptides by bonds
await peptide3.click();

await takeEditorScreenshot(page);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { test, expect } from '@playwright/test';
import { test } from '@playwright/test';
import { selectSingleBondTool, waitForPageInit } from '@utils';
import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
/* eslint-disable no-magic-numbers */

test.describe('Polymer Bond Tool', () => {
Expand All @@ -12,8 +13,7 @@ test.describe('Polymer Bond Tool', () => {
Description: Polymer bond tool
*/

await expect(page.getByTestId('PolymerToggler')).toBeVisible();
await page.getByTestId('PolymerToggler').click();
await turnOnMacromoleculesEditor(page);

// Choose peptide
await page.getByText('Tza').click();
Expand All @@ -25,7 +25,7 @@ test.describe('Polymer Bond Tool', () => {
await page.mouse.click(500, 200);

// Get 4 peptides locators
const peptides = await page.getByText('Tza');
const peptides = await page.getByText('Tza').locator('..');
const peptide1 = peptides.nth(0);
const peptide2 = peptides.nth(1);
const peptide3 = peptides.nth(2);
Expand Down Expand Up @@ -69,8 +69,7 @@ test.describe('Polymer Bond Tool', () => {
Description: Polymer bond tool
*/

await expect(page.getByTestId('PolymerToggler')).toBeVisible();
await page.getByTestId('PolymerToggler').click();
await turnOnMacromoleculesEditor(page);

// Choose chems
await page.getByText('CHEM').click();
Expand All @@ -81,7 +80,7 @@ test.describe('Polymer Bond Tool', () => {
await page.mouse.click(400, 400);

// Get 2 chems locators
const chems = await page.getByText('hxy');
const chems = await page.getByText('hxy').locator('..');
const chem1 = chems.nth(0);
const chem2 = chems.nth(1);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test, expect } from '@playwright/test';
import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
import { test } from '@playwright/test';
import { waitForPageInit } from '@utils/common';

test.describe('Macromolecules default presets', () => {
Expand All @@ -10,8 +11,7 @@ test.describe('Macromolecules default presets', () => {
Test case: #2934 - rna builder: add default presets
Description: Switch to Polymer Editor
*/
await expect(page.getByTestId('PolymerToggler')).toBeVisible();
await page.getByTestId('PolymerToggler').click();
await turnOnMacromoleculesEditor(page);
await page.getByText('RNA').click();

await page.getByTestId('cancel-btn').click();
Expand All @@ -25,8 +25,7 @@ test.describe('Macromolecules default presets', () => {
/*
Test case: #2507 - Add RNA monomers to canvas (by click)
*/
await expect(page.getByTestId('PolymerToggler')).toBeVisible();
await page.getByTestId('PolymerToggler').click();
await turnOnMacromoleculesEditor(page);
await page.getByText('RNA').click();
await page.getByTestId('cancel-btn').click();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { test } from '@playwright/test';
import {
addMonomerToCanvas,
selectEraseTool,
selectRectangleArea,
selectRectangleSelectionTool,
selectSingleBondTool,
} from '@utils';
import { turnOnMacromoleculesEditor } from '@utils/macromolecules';
import { bondTwoMonomers } from '@utils/macromolecules/polymerBond';
/* eslint-disable no-magic-numbers */

test.describe('Rectangle Selection Tool', () => {
test.beforeEach(async ({ page }) => {
await page.goto('');
await turnOnMacromoleculesEditor(page);
});
test.skip('Select monomer and bonds and then erase', async ({ page }) => {
/*
Test case: #2360 - "Select" tool for Macromolecules editor
Description: Rectangle Selection Tool
*/

// Create 4 peptides on canvas
const MONOMER_NAME = 'Tza___3-thiazolylalanine';
const MONOMER_ALIAS = 'Tza';
await addMonomerToCanvas(page, MONOMER_NAME, 300, 300);
await addMonomerToCanvas(page, MONOMER_NAME, 400, 400);
await addMonomerToCanvas(page, MONOMER_NAME, 500, 500);
await addMonomerToCanvas(page, MONOMER_NAME, 500, 200);

// Get 4 peptides locators
const peptides = await page.getByText(MONOMER_ALIAS).locator('..');
const peptide1 = peptides.nth(0);
const peptide2 = peptides.nth(1);
const peptide3 = peptides.nth(2);
const peptide4 = peptides.nth(3);

// Select bond tool
await selectSingleBondTool(page);

// Create bonds between peptides
await bondTwoMonomers(page, peptide1, peptide2);
await bondTwoMonomers(page, peptide3, peptide2);
await bondTwoMonomers(page, peptide3, peptide4);

await page.screenshot({
path: 'tests/Macromolecule-editor/screenshots/rectangle-selection-tool.png',
});

await selectRectangleSelectionTool(page);

// Coordinates for rectangle selection
const startX = 100;
const startY = 100;
const endX = 500;
const endY = 500;

await selectRectangleArea(page, startX, startY, endX, endY);

await page.screenshot({
path: 'tests/Macromolecule-editor/screenshots/rectangle-selection-tool2.png',
});

// Erase selected elements
await selectEraseTool(page);

await page.screenshot({
path: 'tests/Macromolecule-editor/screenshots/rectangle-selection-tool3.png',
});
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions ketcher-autotests/tests/utils/canvas/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,13 @@ export async function resetAllSettingsToDefault(page: Page) {
await pressButton(page, 'Reset');
await pressButton(page, 'Apply');
}

export async function addMonomerToCanvas(
page: Page,
monomerFullName: string,
positionX: number,
positionY: number,
) {
await page.getByTestId(monomerFullName).click();
await page.mouse.click(positionX, positionY);
}
24 changes: 24 additions & 0 deletions ketcher-autotests/tests/utils/canvas/tools/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,30 @@ export async function selectSingleBondTool(page: Page) {
await bondToolButton.click();
}

export async function selectEraseTool(page: Page) {
const bondToolButton = page.locator(`button[title*="Erase"]`);
await bondToolButton.click();
}

export async function selectRectangleSelectionTool(page: Page) {
const bondToolButton = page.locator(`button[title*="select-rectangle"]`);
await bondToolButton.click();
}

export async function selectRectangleArea(
page: Page,
startX: number,
startY: number,
endX: number,
endY: number,
) {
await selectRectangleSelectionTool(page);
await page.mouse.move(startX, startY);
await page.mouse.down();
await page.mouse.move(endX, endY);
await page.mouse.up();
}

export async function selectTopPanelButton(
buttonName: TopPanelButton,
page: Page,
Expand Down
7 changes: 7 additions & 0 deletions ketcher-autotests/tests/utils/macromolecules/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { expect, Page } from '@playwright/test';
import { POLYMER_TOGGLER } from '@constants/testIdConstants';

export async function turnOnMacromoleculesEditor(page: Page) {
await expect(page.getByTestId(POLYMER_TOGGLER)).toBeVisible();
await page.getByTestId(POLYMER_TOGGLER).click();
}
12 changes: 12 additions & 0 deletions ketcher-autotests/tests/utils/macromolecules/polymerBond.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Locator, Page } from '@playwright/test';

export async function bondTwoMonomers(
page: Page,
firstMonomerElement: Locator,
secondMonomerElement: Locator,
) {
await firstMonomerElement.hover();
await page.mouse.down();
await secondMonomerElement.hover();
await page.mouse.up();
}
4 changes: 4 additions & 0 deletions packages/ketcher-core/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"root": false,
"extends": "plugin:jest/recommended",
"rules": {
"@typescript-eslint/no-empty-function": "off",
"no-useless-constructor": "off"
},
"overrides": [
{
"files": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { CoreEditor } from 'application/editor';
import { PeptideRenderer } from 'application/render/renderers/PeptideRenderer';
import {
getFinishedPolymerBond,
peptideMonomerItem,
polymerEditorTheme,
} from '../../../mock-data';
import { createPolymerEditorCanvas } from '../../../helpers/dom';
import { SelectRectangle } from 'application/editor/tools/SelectRectangle';

jest.mock('d3', () => {
return {
brush() {
return {
on() {},
};
},
select() {
return {
call() {
return this;
},
insert() {
return this;
},
select() {
return this;
},
attr() {
return this;
},
style() {
return this;
},
};
},
};
});

describe('Select Rectangle Tool', () => {
it('should select drawing entity on mousedown', () => {
const polymerBond = getFinishedPolymerBond(0, 0, 10, 10);
const event = {
target: {
__data__: polymerBond.renderer,
},
};
const selectRectangleTool = new SelectRectangle(
new CoreEditor({
theme: polymerEditorTheme,
canvas: createPolymerEditorCanvas(),
}),
);

expect(polymerBond.selected).toBeFalsy();
selectRectangleTool.mousedown(event);
expect(polymerBond.selected).toBeTruthy();
});

it('should initiate the render of peptide mousedown', () => {
const canvas: SVGSVGElement = createPolymerEditorCanvas();
const editor: CoreEditor = new CoreEditor({
canvas,
theme: polymerEditorTheme,
});
const onShow = jest.fn();
jest.spyOn(PeptideRenderer.prototype, 'show').mockImplementation(onShow);
editor.events.selectMonomer.dispatch(peptideMonomerItem);
canvas.dispatchEvent(new Event('mouseover', { bubbles: true }));
expect(onShow).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exports[`PeptideRenderer should render peptide 1`] = `
id="polymer-editor-canvas"
width="500"
>
<defs />
<g
transform="translate(0, 0) scale(1)"
transition="transform 0.2s"
Expand All @@ -20,6 +21,7 @@ exports[`PeptideRenderer should render peptide 1`] = `
font-size="12px"
font-weight="700"
line-height="12px"
pointer-events="none"
style="cursor: pointer; user-select: none;"
x="0"
y="10"
Expand Down
Loading

0 comments on commit 19b56df

Please sign in to comment.