diff --git a/packages/ketcher-core/rollup.config.js b/packages/ketcher-core/rollup.config.js index 71438334ae..534b389c51 100644 --- a/packages/ketcher-core/rollup.config.js +++ b/packages/ketcher-core/rollup.config.js @@ -1,15 +1,15 @@ -import ttypescript from 'ttypescript' -import peerDepsExternal from 'rollup-plugin-peer-deps-external' import babel from '@rollup/plugin-babel' -import replace from '@rollup/plugin-replace' -import resolve from '@rollup/plugin-node-resolve' +import cleanup from 'rollup-plugin-cleanup' import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' import del from 'rollup-plugin-delete' -import typescript from 'rollup-plugin-typescript2' -import cleanup from 'rollup-plugin-cleanup' -import strip from '@rollup/plugin-strip' +import json from '@rollup/plugin-json' +import peerDepsExternal from 'rollup-plugin-peer-deps-external' import pkg from './package.json' +import replace from '@rollup/plugin-replace' +import resolve from '@rollup/plugin-node-resolve' +import strip from '@rollup/plugin-strip' +import ttypescript from 'ttypescript' +import typescript from 'rollup-plugin-typescript2' const mode = { PRODUCTION: 'production', @@ -33,16 +33,6 @@ const config = { format: 'es' } ], - external: [ - 'url', - 'remark-parse', - 'unified', - 'asap', - 'object-assign', - 'unist-util-visit', - 'unist-util-visit-parents', - 'xtend' - ], plugins: [ del({ targets: 'dist/*', diff --git a/packages/ketcher-core/src/__tests__/domain/entities/atom.test.ts b/packages/ketcher-core/src/__tests__/domain/entities/atom.test.ts new file mode 100644 index 0000000000..0d5efc6d78 --- /dev/null +++ b/packages/ketcher-core/src/__tests__/domain/entities/atom.test.ts @@ -0,0 +1,504 @@ +import { Atom, radicalElectrons } from 'domain/entities/atom' + +describe('radicalElectrons', () => { + it('should return 1 if passed radical is Douplet (value = 2)', () => { + expect(radicalElectrons(2)).toBe(1) + }) + + it('should return 2 if passed radical is singlet (value = 1) or triplet (value = 3)', () => { + expect(radicalElectrons(1)).toBe(2) + expect(radicalElectrons(3)).toBe(2) + }) + + it.each([4, 'test', {}, null, undefined])( + 'should return 0 if passed radical is different from 1 to 3 value range', + radical => { + expect(radicalElectrons(radical)).toBe(0) + } + ) +}) + +describe('Atom', () => { + const hydrogenParams = { + aam: 0, + alias: null, + atomList: null, + attpnt: null, + badConn: false, + charge: 0, + exactChangeFlag: 0, + explicitValence: -1, + fragment: 0, + hCount: 0, + implicitH: 1, + invRet: 0, + isotope: 0, + label: 'H', + neighbors: [], + pseudo: '', + radical: 0, + rglabel: null, + ringBondCount: 0, + rxnFragmentType: -1, + sgs: new Set(), + stereoLabel: null, + stereoParity: 0, + substitutionCount: 0, + unsaturatedAtom: 0, + valence: 1 + } + + describe('Atom constructor', () => { + it('should create getter function "pseudo" and able to call it', () => { + const atom = new Atom(hydrogenParams) + expect(atom.pseudo).toBe('') + }) + }) + + describe('pseudo getter', () => { + it('should return empty string if value is real label of element', () => { + const atom = new Atom(hydrogenParams) + expect(atom.pseudo).toBe('') + }) + + it('should return empty string if passed value is R#', () => { + const params = { + ...hydrogenParams, + label: 'R#' + } + const atom = new Atom(params) + expect(atom.pseudo).toBe('') + }) + + it('should return empty string if passed value is L', () => { + const params = { + ...hydrogenParams, + label: 'L' + } + const atom = new Atom(params) + expect(atom.pseudo).toBe('') + }) + + it('should return empty string if passed value is L#', () => { + const params = { + ...hydrogenParams, + label: 'L#' + } + const atom = new Atom(params) + expect(atom.pseudo).toBe('') + }) + + it('should return passed label if its not real label and not L, L#, R#', () => { + const params = { + ...hydrogenParams, + label: 'pseudo' + } + const atom = new Atom(params) + expect(atom.pseudo).toBe('pseudo') + }) + }) + + describe('attrGetDefault static function', () => { + it('should return default attr if value is in attrsList', () => { + expect(Atom.attrGetDefault('label')).toBe('C') + }) + + it('should call console.assert if passed value is not in attrsList', () => { + console.assert = jest.fn() + Atom.attrGetDefault('test') + expect(console.assert).toHaveBeenCalled() + }) + }) + + describe('clone', () => { + it('should clone element', () => { + const fidMap = new Map() + const atom = new Atom(hydrogenParams) + const copiedAtom = atom.clone(fidMap) + expect(copiedAtom).not.toBe(atom) + }) + + it('should replace fragment from params to fragment from fidMap', () => { + const fidMap = new Map() + fidMap.set(0, 10) + const atom = new Atom(hydrogenParams) + const copiedAtom = atom.clone(fidMap) + expect(copiedAtom.fragment).not.toBe(atom.fragment) + expect(copiedAtom.fragment).toBe(10) + }) + }) + + describe('isQuery', () => { + it('should return true if atom list is not null', () => { + const hydrogenParamsWithAtomList = { + ...hydrogenParams, + atomList: [] + } + const atom = new Atom(hydrogenParamsWithAtomList as any) + expect(atom.isQuery()).toBe(true) + }) + + it('should return true if label is A', () => { + const paramsWithALabel = { + ...hydrogenParams, + label: 'A' + } + const atom = new Atom(paramsWithALabel) + expect(atom.isQuery()).toBe(true) + }) + + it('should return truthy value if params have attpnt prop', () => { + const paramsWithAttpnt = { + ...hydrogenParams, + attpnt: 'test' + } + const atom = new Atom(paramsWithAttpnt) + expect(atom.isQuery()).toBeTruthy() + }) + + it('should return truthy value if params have hCount prop', () => { + const paramsWithHCount = { + ...hydrogenParams, + hCount: 10 + } + const atom = new Atom(paramsWithHCount) + expect(atom.isQuery()).toBeTruthy() + }) + + it('should return falsy value if it is default atom', () => { + const atom = new Atom(hydrogenParams) + expect(atom.isQuery()).toBeFalsy() + }) + }) + + describe('pureHydrogen', () => { + it('should return true if label is "H" and isotope = 0', () => { + const atom = new Atom(hydrogenParams) + expect(atom.pureHydrogen()).toBe(true) + }) + + it('should return false if label is "H" and isotope != 0', () => { + const hydrogenParamsWithIsotope = { + ...hydrogenParams, + isotope: 1 + } + const atom = new Atom(hydrogenParamsWithIsotope) + expect(atom.pureHydrogen()).toBe(false) + }) + + it('should return false if label is not "H" and isotope = 0', () => { + const atomParams = { + ...hydrogenParams, + label: 'C' + } + const atom = new Atom(atomParams) + expect(atom.pureHydrogen()).toBe(false) + }) + }) + + describe('isPlainCarbon', () => { + const plainCarbonParams = { + ...hydrogenParams, + label: 'C' + } + + it('should return true if it is plain carbon', () => { + const atom = new Atom(plainCarbonParams) + expect(atom.isPlainCarbon()).toBe(true) + }) + + it('should return false if it is not carbon', () => { + const atom = new Atom(hydrogenParams) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and isotope != 0', () => { + const carbonWithIsotopeParam = { + ...plainCarbonParams, + isotope: 1 + } + const atom = new Atom(carbonWithIsotopeParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and radical != 0', () => { + const carbonWithRadicalParam = { + ...plainCarbonParams, + radical: 1 + } + const atom = new Atom(carbonWithRadicalParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and charge != 0', () => { + const carbonWithChargeParam = { + ...plainCarbonParams, + charge: 1 + } + const atom = new Atom(carbonWithChargeParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and explicit valence >= 0', () => { + const noExpValenceParams = { + ...plainCarbonParams, + explicitValence: 0 + } + const atom = new Atom(noExpValenceParams) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and ringBondCount > 0', () => { + const carbonWithRingBondCountParam = { + ...plainCarbonParams, + ringBondCount: 1 + } + const atom = new Atom(carbonWithRingBondCountParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and substitutionCount > 0', () => { + const carbonWithSubstitutionCountParam = { + ...plainCarbonParams, + substitutionCount: 1 + } + const atom = new Atom(carbonWithSubstitutionCountParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and unsaturatedAtom > 0', () => { + const carbonWithUnsaturatedAtomParam = { + ...plainCarbonParams, + unsaturatedAtom: 1 + } + const atom = new Atom(carbonWithUnsaturatedAtomParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and hCount > 0', () => { + const carbonWithHCountParam = { + ...plainCarbonParams, + hCount: 1 + } + const atom = new Atom(carbonWithHCountParam) + expect(atom.isPlainCarbon()).toBe(false) + }) + + it('should return false if it is carbon and it has atomList', () => { + const carbonWithAtomListParam = { + ...plainCarbonParams, + atomList: [] + } + const atom = new Atom(carbonWithAtomListParam as any) + expect(atom.isPlainCarbon()).toBe(false) + }) + }) + + describe('isPseudo', () => { + it('should return false if atom has atomList', () => { + const paramsWithAtomList = { + ...hydrogenParams, + atomList: [] + } + + const atom = new Atom(paramsWithAtomList as any) + expect(atom.isPseudo()).toBe(false) + }) + + it('should return false if atom has rgLabel', () => { + const paramsWithRgLabel = { + ...hydrogenParams, + rglabel: 'test' + } + + const atom = new Atom(paramsWithRgLabel) + expect(atom.isPseudo()).toBe(false) + }) + + it('should return false if atom has not pseudo label', () => { + const atom = new Atom(hydrogenParams) + expect(atom.isPseudo()).toBe(false) + }) + + it('should return true if atom has pseudo label and does not have atomList and rglabel', () => { + const paramsWithRgLabel = { + ...hydrogenParams, + label: 'pseudo' + } + + const atom = new Atom(paramsWithRgLabel) + expect(atom.isPseudo()).toBe(true) + }) + }) + + describe('hasRxnProps', () => { + it('should return true if atom has invRet > 0', () => { + const paramsWithInvRet = { + ...hydrogenParams, + invRet: 1 + } + + const atom = new Atom(paramsWithInvRet) + expect(atom.hasRxnProps()).toBe(true) + }) + + it('should return true if atom has exactChangeFlag > 0', () => { + const paramsWithexactChangeFlag = { + ...hydrogenParams, + exactChangeFlag: 1 + } + + const atom = new Atom(paramsWithexactChangeFlag) + expect(atom.hasRxnProps()).toBe(true) + }) + + it('should return true if atom has attPnt > 0', () => { + const paramsWithAttpnt = { + ...hydrogenParams, + attpnt: 1 + } + + const atom = new Atom(paramsWithAttpnt) + expect(atom.hasRxnProps()).toBe(true) + }) + + it('should return true if atom has aam > 0', () => { + const paramsWithAam = { + ...hydrogenParams, + aam: 1 + } + + const atom = new Atom(paramsWithAam) + expect(atom.hasRxnProps()).toBe(true) + }) + + it('should return false for default hydrogen', () => { + const atom = new Atom(hydrogenParams) + expect(atom.hasRxnProps()).toBe(false) + }) + }) + + describe('calcValence', () => { + it('should return true and set inplicitH = 0 if atom is query', () => { + const queryAtomParams = { + ...hydrogenParams, + attpnt: 5, + implicitH: 10 + } + const atom = new Atom(queryAtomParams) + expect(atom.implicitH).toBe(10) + expect(atom.calcValence(0)).toBe(true) + expect(atom.implicitH).toBe(0) + }) + + it('should return true and set inplicitH = 0 if atom label is not from PT', () => { + const pseudoAtomParams = { + ...hydrogenParams, + label: 'test', + implicitH: 5 + } + + const pseudoAtom = new Atom(pseudoAtomParams) + expect(pseudoAtom.implicitH).toBe(5) + expect(pseudoAtom.calcValence(5)).toBe(true) + expect(pseudoAtom.implicitH).toBe(0) + }) + + it('should set valence = 1 for group 1 elements', () => { + const LiParams = { + ...hydrogenParams, + label: 'Li' + } + + const hydrogen = new Atom(hydrogenParams) + const litium = new Atom(LiParams) + + expect(hydrogen.calcValence(0)).toBe(true) + expect(hydrogen.valence).toBe(1) + expect(litium.calcValence(0)).toBe(true) + expect(litium.valence).toBe(1) + }) + + // TODO: Add other test cases for calcValence function + }) + + describe('calcValenceMinusHyd', () => { + it("should return 0 if Elements doesn't contain label", () => { + const paramsWithALabel = { + ...hydrogenParams, + label: 'test' + } + + const atom = new Atom(paramsWithALabel) + + expect(atom.calcValenceMinusHyd(3)).toBe(0) + }) + + it("should return rad + conn <= 4 if label = B charge = doesn't contain label", () => { + const paramsWithALabel = { + ...hydrogenParams, + label: 'B', + charge: -1 + } + + const atom = new Atom(paramsWithALabel) + + expect(atom.calcValenceMinusHyd(3)).toBeLessThanOrEqual(4) + }) + + it.each(['B', 'Al', 'Ga', 'In'])( + 'should return number <= 4 if group = 3 label = %p, charge = -1', + label => { + const paramsWithALabel = { + ...hydrogenParams, + label, + charge: -1 + } + + const atom = new Atom(paramsWithALabel) + + expect(atom.calcValenceMinusHyd(3)).toBeLessThanOrEqual(4) + } + ) + + it.each([ + ['N', 1, 2], + ['P', 1, 2], + ['Sb', 1, 2], + ['Bi', 1, 2], + ['As', 1, 2], + ['N', 2, 2], + ['P', 2, 2], + ['Sb', 2, 2], + ['Bi', 2, 2], + ['As', 2, 2], + ['O', 1, 2], + ['O', 2, 2], + ['O', 3, 2], + ['S', 1, 2], + ['Se', 1, 2], + ['Po', 1, 2], + ['Cl', 1, 2], + ['Br', 1, 2], + ['I', 1, 2], + ['At', 1, 2], + ['Og', 1, 3], + ['Ts', 1, 3], + ['Lv', 1, 3] + ])( + 'should for label %p and charge %p return %p', + (label, charge, expected) => { + const paramsWithALabel = { + ...hydrogenParams, + label, + charge, + radical: 0 + } + + const atom = new Atom(paramsWithALabel) + + expect(atom.calcValenceMinusHyd(2)).toBe(expected) + } + ) + }) +}) diff --git a/packages/ketcher-core/src/__tests__/domain/entities/atomList.test.ts b/packages/ketcher-core/src/__tests__/domain/entities/atomList.test.ts new file mode 100644 index 0000000000..733cd480dc --- /dev/null +++ b/packages/ketcher-core/src/__tests__/domain/entities/atomList.test.ts @@ -0,0 +1,46 @@ +import { AtomList } from 'domain/entities/atomList' + +const ids = [66, 44, 12, 88] +const params = { notList: false, ids } + +describe('labelList', () => { + it('should return array of elements labels', () => { + const atomList = new AtomList(params) + + expect(atomList.labelList()).toStrictEqual(['Dy', 'Ru', 'Mg', 'Ra']) + }) +}) + +describe('label', () => { + it('should return list', () => { + const atomList = new AtomList(params) + + expect(atomList.label()).toBe('[Dy,Ru,Mg,Ra]') + }) + + it('should return not list', () => { + const atomList = new AtomList({ ...params, notList: true }) + + expect(atomList.label()).toBe('![Dy,Ru,Mg,Ra]') + }) +}) +describe('equals', () => { + it.each([false, true])('should return true', notList => { + const atomList = new AtomList({ ...params, notList }) + const dataWithReverseIds = { notList, ids: params.ids.sort().reverse() } + const atomList2 = new AtomList(dataWithReverseIds) + + expect(atomList.equals(atomList2)).toBeTruthy() + }) + + it('should return false', () => { + const atomList = new AtomList(params) + const dataWithReverseIds = { + notList: true, + ids: params.ids.sort().reverse() + } + const atomList2 = new AtomList(dataWithReverseIds) + + expect(atomList.equals(atomList2)).toBeFalsy() + }) +}) diff --git a/packages/ketcher-core/src/__tests__/domain/entities/bond.test.ts b/packages/ketcher-core/src/__tests__/domain/entities/bond.test.ts new file mode 100644 index 0000000000..a1c5ab9682 --- /dev/null +++ b/packages/ketcher-core/src/__tests__/domain/entities/bond.test.ts @@ -0,0 +1,105 @@ +import { Bond, BondAttributes } from 'domain/entities/bond' + +import { Vec2 } from 'domain/entities/vec2' + +const bondParams: BondAttributes = { + begin: 1, + end: 2, + type: 1, + stereo: 0, + topology: 1 +} + +describe('Bond', () => { + describe('getAttrHash static function', () => { + it('should return attributes', () => { + const bond = new Bond(bondParams) + const attrs = { + stereo: 0, + topology: 1, + type: 1 + } + + expect(Bond.getAttrHash(bond)).toStrictEqual(attrs) + }) + }) + + describe('attrGetDefault static function', () => { + it('should return attribute value', () => { + expect(Bond.attrGetDefault('stereo')).toBe(0) + expect(Bond.attrGetDefault('topology')).toBe(0) + expect(Bond.attrGetDefault('type')).toBe(1) + expect(Bond.attrGetDefault('reactingCenterStatus')).toBe(0) + }) + }) + + describe('hasRxnProps', () => { + it('should return true if bond has reactingCenterStatus > 0', () => { + const paramsWithReactingCenterStatus = { + ...bondParams, + reactingCenterStatus: 1 + } + const bond = new Bond(paramsWithReactingCenterStatus) + + expect(bond.hasRxnProps()).toBe(true) + }) + + it('should return false if bond has not reactingCenterStatus', () => { + const paramsWithReactingCenterStatus = { + ...bondParams, + reactingCenterStatus: 0 + } + const bond = new Bond(paramsWithReactingCenterStatus) + + expect(bond.hasRxnProps()).toBe(false) + }) + }) + + describe('getCenter', () => { + it('should return center of bond', () => { + const bond = new Bond(bondParams) + const struct = { atoms: new Map() } + struct.atoms.set(bond.begin, { pp: new Vec2(2, 4, 6) }) + struct.atoms.set(bond.end, { pp: new Vec2(4, 0, 2) }) + const bondCenter = new Vec2(3, 2, 4) + + expect(bond.getCenter(struct)).toStrictEqual(bondCenter) + }) + }) + + describe('getDir', () => { + it('should return direction', () => { + const bond = new Bond(bondParams) + const struct = { atoms: new Map() } + struct.atoms.set(bond.begin, { pp: new Vec2(2, 4, 6) }) + struct.atoms.set(bond.end, { pp: new Vec2(4, 0, 2) }) + const bondDir = new Vec2( + 0.4472135954999579, + -0.8944271909999159, + -0.8944271909999159 + ) + + expect(bond.getDir(struct)).toStrictEqual(bondDir) + }) + }) + + describe('clone', () => { + it('should return copy of bond if do not pass the arguments', () => { + const bond = new Bond(bondParams) + + expect(bond.clone()).toStrictEqual(bond) + }) + + it('should return copy of bond with new begin and end coordinates', () => { + const bond = new Bond(bondParams) + const aidMap = new Map() + const newBegin = 2 + const newEnd = 3 + aidMap.set(1, newBegin) + aidMap.set(2, newEnd) + const bondCopy = new Bond({ ...bondParams, begin: newBegin, end: newEnd }) + + expect(bond.clone(aidMap)).toStrictEqual(bondCopy) + }) + }) +}) diff --git a/packages/ketcher-core/src/__tests__/domain/entities/box2Abs.test.ts b/packages/ketcher-core/src/__tests__/domain/entities/box2Abs.test.ts new file mode 100644 index 0000000000..a95de35e80 --- /dev/null +++ b/packages/ketcher-core/src/__tests__/domain/entities/box2Abs.test.ts @@ -0,0 +1,18 @@ +import { Vec2 } from 'domain/entities/vec2' +import { Box2Abs } from 'domain/entities/box2Abs' + +describe('clone', () => { + it('should return clone', () => { + const box2Abs = new Box2Abs() + const box2AbsClone = box2Abs.clone() + const p0 = new Vec2(box2Abs.p0) + const p1 = new Vec2(box2Abs.p1) + const p2 = box2AbsClone.p0 + const p3 = box2AbsClone.p1 + + const isClone = + box2Abs.clone() instanceof Box2Abs && p0.equals(p1) && p2.equals(p3) + + expect(isClone).toBeTruthy() + }) +}) diff --git a/packages/ketcher-core/src/__tests__/domain/entities/vec2.test.ts b/packages/ketcher-core/src/__tests__/domain/entities/vec2.test.ts new file mode 100644 index 0000000000..0901973d9e --- /dev/null +++ b/packages/ketcher-core/src/__tests__/domain/entities/vec2.test.ts @@ -0,0 +1,234 @@ +import { Vec2 } from 'domain/entities/vec2' + +describe('length', () => { + it('should show vector length', () => { + const v0 = new Vec2(3, 3, 3) + + expect(v0.length()).toBe(4.242640687119285) + }) +}) + +describe('equals', () => { + it.each([ + [true, [3, 3, 3], [3, 3, 3]], + [false, [3, 3, 3], [2, 2, 2]] + ])('should return %p', (expected, v0Args, v1Args) => { + const v0 = new Vec2(...v0Args) + const v1 = new Vec2(...v1Args) + + expect(v0.equals(v1)).toBe(expected) + }) +}) + +describe('add', () => { + it('should return new vector the sum of two vectors', () => { + const v0 = new Vec2(1, 1, 1) + const v1 = new Vec2(1, 1, 1) + const v2 = v0.add(v1) + const v3 = new Vec2(2, 2, 2) + + expect(v2.equals(v3) && v0 !== v2 && v1 !== v2).toBeTruthy() + }) +}) + +describe('add_', () => { + it('should add the vector to the current vector', () => { + const v0 = new Vec2(1, 1, 1) + const v1 = new Vec2(1, 1, 1) + const v2 = new Vec2(2, 2, 2) + + v0.add_(v1) + + expect(v0.equals(v2)).toBeTruthy() + }) +}) + +describe('get_xy0', () => { + it('should return true if new vector with current x and y, z = 0', () => { + const v0 = new Vec2(3, 3, 3) + const v1 = new Vec2(3, 3, 0) + + expect(v0.get_xy0().equals(v1)).toBeTruthy() + }) +}) + +describe('sub', () => { + it('should return true if a new vector which is equal to the difference of 2 vectors', () => { + const v0 = new Vec2(3, 3, 3) + const v1 = new Vec2(1, 1, 1) + const v2 = new Vec2(2, 2, 2) + + const result = v0.sub(v1) + + expect(result.equals(v2)).toBeTruthy() + }) +}) + +describe('scaled', () => { + it('should return true if the coordinates of the new one are multiplied by 3', () => { + const v0 = new Vec2(3, 3, 3) + const v1 = new Vec2(9, 9, 9) + + expect(v0.scaled(3).equals(v1)).toBeTruthy() + }) + + it('should return true if the coordinates of the new one are multiplied by 0', () => { + const v0 = new Vec2(3, 3, 3) + const v1 = new Vec2(0, 0, 0) + + expect(v0.scaled(0).equals(v1)).toBeTruthy() + }) +}) + +describe('negated', () => { + it('should return true if vector coordinates become negative', () => { + const v0 = new Vec2(2, 2, 2) + const v1 = new Vec2(-2, -2, -2) + + expect(v0.negated().equals(v1)).toBeTruthy() + }) +}) + +describe('yComplement', () => { + it.each([ + [true, -3, 3], + [true, -6, 0], + [false, 5, 0] + ])('should return %p if y = %p, y1 = %p', (expected, y, y1) => { + const v0 = new Vec2(3, 6, 3) + const v1 = new Vec2(3, y, 3) + + expect(v0.yComplement(y1).equals(v1)).toBe(expected) + }) +}) + +describe('addScaled', () => { + it('should return true if v0 = v1', () => { + const v0 = new Vec2(3, 3, 3) + const v1 = new Vec2(3, 3, 3) + const v2 = new Vec2(12, 12, 12) + + expect(v0.addScaled(v1, 3).equals(v2)).toBeTruthy() + }) +}) + +describe('normalized', () => { + it('should return true if v0 = v1', () => { + const v0 = new Vec2(3, 2, 1) + const v1 = new Vec2( + 0.8320502943378437, + 0.5547001962252291, + 0.2773500981126146 + ) + + expect(v0.normalized().equals(v1)).toBe(true) + }) +}) + +describe('normalize', () => { + it('should return true if length < 0.000001', () => { + const v0 = new Vec2(0, 0, 0) + const defaultV0 = new Vec2(0, 0, 0) + const isSideEffect = !v0.equals(defaultV0) + + const result = v0.normalize() + + expect(!result && !isSideEffect).toBeTruthy() + }) + + it('should return true if length > 0.000001', () => { + const v0 = new Vec2(2, 2, 2) + const defaultV0 = new Vec2(2, 2, 2) + const result = v0.normalize() + const isSideEffect = !v0.equals(defaultV0) + + expect(result && isSideEffect).toBeTruthy() + }) +}) + +describe('turnLeft', () => { + it('should return true if y of the new vector becomes negative', () => { + const v0 = new Vec2(2, 2, 2) + + const result = Math.sign(v0.turnLeft().y) + + expect(result).toBeTruthy() + }) +}) + +describe('coordStr', () => { + test('should retrun string with x, y', () => { + const v0 = new Vec2(2, 2, 2) + + expect(v0.coordStr()).toBe('2 , 2') + }) +}) + +describe('toString', () => { + test('should return string with x, y', () => { + const v0 = new Vec2(2, 2, 2) + + expect(v0.toString()).toBe('(2.00,2.00)') + }) +}) + +describe('max', () => { + test('should return true if the new vector with the largest xyz', () => { + const v0 = new Vec2(4, 2, 2) + const v1 = new Vec2(3, 3, 5) + const v2 = new Vec2(4, 3, 5) + + expect(v0.max(v1).equals(v2)).toBeTruthy() + }) +}) + +describe('min', () => { + test('should return true if the new vector with the smallest xyz', () => { + const v0 = new Vec2(4, 2, 2) + const v1 = new Vec2(3, 3, 5) + const v2 = new Vec2(3, 2, 2) + + expect(v0.min(v1).equals(v2)).toBeTruthy() + }) +}) + +describe('ceil', () => { + test('must return true if a new vector is returned with coordinates rounded to a larger integer', () => { + const v0 = new Vec2(2.2, 1.1, 3.3) + const v1 = new Vec2(3, 2, 4) + + expect(v0.ceil().equals(v1)).toBeTruthy() + }) +}) + +describe('floor', () => { + test('should return true if a new vector is returned with coordinates rounded to a smallest integer', () => { + const v0 = new Vec2(2.2, 1.1, 3.3) + const v1 = new Vec2(2, 1, 3) + + expect(v0.floor().equals(v1)).toBeTruthy() + }) +}) + +describe('rotate', () => { + // TODO + test('should true if x = x *', () => { + const v0 = new Vec2(2, 1, 3) + const v1 = new Vec2(-0.39576750238188574, -2.200765340525519, 3) + + expect(v0.rotate(180).equals(v1)).toBeTruthy() + }) +}) + +describe('rotateSC', () => { + // TODO + test('should', () => {}) +}) + +describe('oxAngle', () => { + test('should returns the arctangent of x y', () => { + const v0 = new Vec2(2, 1, 3) + + expect(v0.oxAngle()).toBe(0.4636476090008061) + }) +}) diff --git a/packages/ketcher-core/src/domain/entities/box2Abs.ts b/packages/ketcher-core/src/domain/entities/box2Abs.ts index 49df149480..57e042d80f 100644 --- a/packages/ketcher-core/src/domain/entities/box2Abs.ts +++ b/packages/ketcher-core/src/domain/entities/box2Abs.ts @@ -20,6 +20,7 @@ export class Box2Abs { readonly p0: Vec2 readonly p1: Vec2 + constructor() constructor(p: Vec2) constructor(p0: Vec2, p1: Vec2) constructor(x0: number, y0: number, x1: number, y1: number) diff --git a/packages/ketcher-core/src/domain/entities/vec2.ts b/packages/ketcher-core/src/domain/entities/vec2.ts index 12bf1cf372..ad311d54c5 100644 --- a/packages/ketcher-core/src/domain/entities/vec2.ts +++ b/packages/ketcher-core/src/domain/entities/vec2.ts @@ -117,7 +117,7 @@ export class Vec2 { } equals(v: Vec2): boolean { - return this.x === v.x && this.y === v.y + return this.x === v.x && this.y === v.y && this.z === v.z } add(v: Vec2): Vec2 { @@ -191,11 +191,11 @@ export class Vec2 { return Vec2.min(this, v) } - ceil() { + ceil(): Vec2 { return new Vec2(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z)) } - floor() { + floor(): Vec2 { return new Vec2(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z)) } diff --git a/packages/ketcher-react/rollup.config.js b/packages/ketcher-react/rollup.config.js index 52173c95c8..c6ddae2f45 100644 --- a/packages/ketcher-react/rollup.config.js +++ b/packages/ketcher-react/rollup.config.js @@ -22,8 +22,7 @@ const mode = { const extensions = ['.js', '.jsx', '.ts', '.tsx'] const isProduction = process.env.NODE_ENV === mode.PRODUCTION -const enableFeaturesInDevelopment = - process.env.FEATURES_IN_DEVELOPMENT !== 'disabled' + const config = { input: pkg.source, output: [ @@ -38,32 +37,19 @@ const config = { format: 'es' } ], - external: [ - 'url', - 'remark-parse', - 'unified', - 'asap', - 'object-assign', - 'unist-util-visit', - 'unist-util-visit-parents', - 'xtend' - ], plugins: [ del({ targets: 'dist/*', runOnce: true }), peerDepsExternal({ includeDependencies: true }), - resolve({ extensions, preferBuiltins: true }), + resolve({ extensions, preferBuiltins: false }), commonjs({ sourceMap: false }), replace( { 'process.env.NODE_ENV': JSON.stringify( isProduction ? mode.PRODUCTION : mode.DEVELOPMENT ), - 'process.env.ENABLE_STEREOCHEMISTRY': JSON.stringify( - enableFeaturesInDevelopment - ), 'process.env.VERSION': JSON.stringify(pkg.version), 'process.env.BUILD_DATE': JSON.stringify( new Date().toISOString().slice(0, 19) diff --git a/packages/ketcher-react/src/script/ui/views/toolbars/RightToolbar/RightToolbar.tsx b/packages/ketcher-react/src/script/ui/views/toolbars/RightToolbar/RightToolbar.tsx index ed3b418ab8..3b6d2a2797 100644 --- a/packages/ketcher-react/src/script/ui/views/toolbars/RightToolbar/RightToolbar.tsx +++ b/packages/ketcher-react/src/script/ui/views/toolbars/RightToolbar/RightToolbar.tsx @@ -21,12 +21,12 @@ import { ToolbarGroupItemProps } from '../ToolbarGroupItem' +import { ArrowScroll } from '../ArrowScroll' import { AtomsList } from './AtomsList' import { basicAtoms } from '../../../action/atoms' import classes from './RightToolbar.module.less' import clsx from 'clsx' import { useInView } from 'react-intersection-observer' -import { ArrowScroll } from '../ArrowScroll' const Group: FC<{ className?: string }> = ({ children, className }) => (