Skip to content

Commit

Permalink
Merge pull request #4 from MO-Movia/unit_tests
Browse files Browse the repository at this point in the history
Unit tests
  • Loading branch information
melgish authored Jun 17, 2021
2 parents 2e37bf1 + 3f4c9bf commit cd19829
Show file tree
Hide file tree
Showing 11 changed files with 737 additions and 62 deletions.
471 changes: 471 additions & 0 deletions flow-typed/npm/prosemirror-model_v1.x.x.js

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions flow-typed/prosemirror-model.js

This file was deleted.

4 changes: 0 additions & 4 deletions jest.config.js

This file was deleted.

2 changes: 0 additions & 2 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// setup for jest because jquery is needed by node-mathquill
window.jQuery = require('jquery');
// needed to mock this due to execute during loading
document.execCommand =
document.execCommand || function execCommandMock() {};
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 17 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@modusoperandi/licit-doc-attrs-step",
"version": "0.1.0",
"version": "0.1.1",
"subversion": "1",
"description": "Module that extend Step, overriding the apply, invert, map, getMap and fromJSON methods, and registering your class with a unique JSON-serialization identifier using Step.jsonID.",
"main": "dist/index.js",
Expand All @@ -17,7 +17,8 @@
"flow": "flow --show-all-errors",
"lint": "eslint \"src/**/*.js\"",
"prepare": "npm run build:dist",
"test": "jest --coverage"
"test": "jest --coverage",
"debug": "node --debug-brk --inspect ./node_modules/.bin/jest -i"
},
"devDependencies": {
"@babel/cli": "^7.10.4",
Expand Down Expand Up @@ -96,7 +97,21 @@
]
},
"jest": {
"setupFilesAfterEnv": [
"jest-prosemirror/environment"
],
"testEnvironment": "jsdom",
"collectCoverage": true,
"collectCoverageFrom": [
"*.js"
],
"verbose": true,
"testTimeout": 30000,
"rootDir": "src",
"testRegex": "((\\.|/*.)(test))\\.js?$",
"moduleFileExtensions": [
"js"
],
"transform": {
"^.+\\.jsx?$": "babel-jest"
},
Expand Down
9 changes: 4 additions & 5 deletions src/KeyCommand.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {Transform} from 'prosemirror-transform';
import {EditorView} from 'prosemirror-view';
import {createEditor, doc, p} from 'jest-prosemirror';


describe('KeyCommand', () => {
const HELLO = 'hello';
// Mockup execute method to insert text to compare later.
Expand All @@ -32,7 +31,7 @@ describe('KeyCommand', () => {
['Mod-A']: executeMock,
});

test('PluginKeyBindings', () => {
it('should plugin key map work', () => {
createEditor(doc(p('<cursor>')), {plugins: [plugin]})
.shortcut('Mod-A')
.callback((content) => {
Expand All @@ -48,19 +47,19 @@ describe('KeyCommand', () => {
const NAME = 'Citation';
const KEY = NAME + 'Plugin$';

test('SetPluginKey With Spec', () => {
it('should set Plugin key when plugin having spec', () => {
plugin = setPluginKey(plugin, NAME);
expect(plugin.key).toEqual(KEY);
});

test('SetPluginKey Without Spec', () => {
it('should set plugin key when plugin spec is not set', () => {
plugin.spec = undefined;
plugin.key = undefined;
plugin = setPluginKey(plugin, NAME);
expect(plugin.key).not.toEqual(KEY);
});

test('KeyMapping', () => {
it('should handle os based key map', () => {
const TRIAL = 'Trial';
const keymap0 = makeKeyMap(TRIAL, 'Alt-0', 'Alt-0', 'Alt-0');
const keymap1 = makeKeyMapWithCommon(TRIAL, 'Alt-0');
Expand Down
45 changes: 21 additions & 24 deletions src/UICommand.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import {EditorState, Selection} from 'prosemirror-state';
import {EditorState, Selection, Transaction} from 'prosemirror-state';
import {Transform} from 'prosemirror-transform';
import {EditorView} from 'prosemirror-view';

Expand All @@ -13,27 +13,6 @@ const EventType = {
MOUSEENTER: 'mouseenter',
};

function dryRunEditorStateProxyGetter(
state: EditorState,
propKey: string
): any {
const val = state[propKey];
if (propKey === 'tr' && val instanceof Transform) {
return val.setMeta('dryrun', true);
}
return val;
}

function dryRunEditorStateProxySetter(
state: EditorState,
propKey: string,
propValue: any
): boolean {
state[propKey] = propValue;
// Indicate success
return true;
}

class UICommand {
static EventType = EventType;

Expand Down Expand Up @@ -62,14 +41,32 @@ class UICommand {

const dryRunState = fnProxy
? new fnProxy(state, {
get: dryRunEditorStateProxyGetter,
set: dryRunEditorStateProxySetter,
get: this.dryRunEditorStateProxyGetter,
set: this.dryRunEditorStateProxySetter,
})
: state;

return this.execute(dryRunState, null, view);
};

dryRunEditorStateProxyGetter = (state: EditorState, propKey: string): any => {
const val = state[propKey];
if (propKey === 'tr' && val instanceof Transaction) {
return val.setMeta('dryrun', true);
}
return val;
};

dryRunEditorStateProxySetter = (
state: EditorState,
propKey: string,
propValue: any
): boolean => {
state[propKey] = propValue;
// Indicate success
return true;
};

execute = (
state: EditorState,
dispatch: ?(tr: Transform) => void,
Expand Down
138 changes: 138 additions & 0 deletions src/UICommand.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import UICommand from './UICommand';
import {Transaction} from 'prosemirror-state';
import {createEditor, doc, p} from 'jest-prosemirror';

describe('UICommand', () => {
const editor = createEditor(doc(p('<cursor>')));

beforeAll(() => {
// Create a spy on console (console.error in this case) and provide some mocked implementation
// In mocking global objects it's usually better than simple `jest.fn()`
// because you can `unmock` it in clean way doing `mockRestore`
jest.spyOn(console, 'error').mockImplementation(() => {});
});

afterAll(() => {
// Restore mock after all tests are done, so it won't affect other test suites
console.error.mockRestore();
});

describe('isEnabled', () => {
let uiCmd: UICommand;

beforeEach(() => (uiCmd = new UICommand()));

describe('when command is enabled', () => {
xit('should return truthy value', () => {
// TODO: replace this comment with steps to enable the command.
// So skipping this for now

const output = uiCmd.isEnabled(editor.state, editor.view);

expect(output).toBeTruthy();
});
});

describe('when command is not enabled', () => {
xit('should return falsy value', () => {
// TODO: replace this comment with steps to disable the command.
// So skipping this for now

const output = uiCmd.isEnabled(editor.state, editor.view);

expect(output).toBeFalsy();
});
});
});

it('should respond to UI event', () => {
const uiCmd = new UICommand();
const respond = uiCmd.shouldRespondToUIEvent({
type: UICommand.EventType.CLICK,
});
expect(respond).toEqual(true);
});

it('should execute custom', () => {
const uiCmd = new UICommand();
const tr = uiCmd.executeCustom(editor.state, editor.state.tr, 0, 0);
expect(tr.doc).toBe(editor.state.tr.doc);
});

it('should not be active by default', () => {
const uiCmd = new UICommand();
const active = uiCmd.isActive(editor.state);
expect(active).toEqual(false);
});

it('should label be null by default', () => {
const uiCmd = new UICommand();
const label = uiCmd.renderLabel(editor.state);
expect(label).toEqual(null);
});

it('should be disabled if error thrown', () => {
const uiCmd = new UICommand();
const mockWFUI = jest.fn();
mockWFUI.mockReturnValue(Promise.reject('this is error'));
uiCmd.waitForUserInput = mockWFUI;
const enabled = uiCmd.isEnabled(editor.state, editor.view);
expect(enabled).toEqual(false);
});

xit('should set transaction meta data dryrun to true', () => {
const uiCmd = new UICommand();
const obj = uiCmd.dryRunEditorStateProxyGetter(editor.state, 'tr');
expect(obj).toBeInstanceOf(Transaction);

// TODO: Generally tests should not branch.
// During execution line 86 will abort the test if it does not pass.
// Therefore you will never get to line 92 if it's not a Transaction

if (obj instanceof Transaction) {
const meta = obj.getMeta('dryrun');
expect(meta).toEqual(true);
}
});

describe('dryRunEditorStateProxyGetter', () => {
let tr: Transaction;
let state;
let uiCmd: UICommand;

beforeEach(() => {
tr = new Transaction({});
tr.setMeta = jest.fn().mockImplementation(() => tr);
// use same spy for both cases
state = {tr, other: tr};
uiCmd = new UICommand();
});

describe('when getting the transaction', () => {
it('should update transaction metadata', () => {
const output = uiCmd.dryRunEditorStateProxyGetter(state, 'tr');

expect(tr.setMeta).toHaveBeenCalled();
expect(output).toBe(state.tr);
});
});

describe('when getting other data', () => {
it('should not update transaction metadata', () => {
const output = uiCmd.dryRunEditorStateProxyGetter(state, 'other');

expect(tr.setMeta).not.toHaveBeenCalled();
expect(output).toBe(state.other);
});
});
});

describe('dryRunEditorStateProxySetter', () => {
it('should set state property', () => {
const uiCmd = new UICommand();
const testVal = 'xVal';
uiCmd.dryRunEditorStateProxySetter(editor.state, 'xTest', testVal);
expect(editor.state.xTest).toEqual(testVal);
});
});
});
29 changes: 10 additions & 19 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class SetDocAttrStep extends Step {
this.value = value;
}

apply(doc: Node): void {
apply(doc: Node): StepResult {
this.prevValue = doc.attrs[this.key];
// avoid clobbering doc.type.defaultAttrs
// this shall take care of focus out issue too.
Expand All @@ -49,24 +49,12 @@ export class SetDocAttrStep extends Step {
// [FS] IRAD-1010 2020-07-27
// Handle map properly so that undo works correctly for document attritube changes.
map(mapping: Mappable): ?SetDocAttrStep {
const from = mapping.mapResult(this.from, 1),
to = mapping.mapResult(this.to, -1);
if (from.deleted && to.deleted) {
return null;
}
return new SetDocAttrStep(this.key, this.value, STEPNAME_SDA);
// position never changes so map should always return same step
return this;
}

merge(other: SetDocAttrStep): ?SetDocAttrStep {
if (
other instanceof SetDocAttrStep &&
// [FS] IRAD-1028 2020-09-30
// validate mark
other.mark &&
other.mark.eq(this.mark) &&
this.from <= other.to &&
this.to >= other.from
) {
if (other instanceof SetDocAttrStep) {
return new SetDocAttrStep(this.key, this.value, STEPNAME_SDA);
}
return null;
Expand All @@ -80,18 +68,21 @@ export class SetDocAttrStep extends Step {
};
}

static fromJSON(schema: any, json: SetDocAttrStepJSONValue) {
static fromJSON(schema: any, json: SetDocAttrStepJSONValue): SetDocAttrStep {
return new SetDocAttrStep(json.key, json.value, json.stepType);
}

static register() {
static register(): boolean {
try {
// [FS] IRAD-899 2020-03-13
// Register this step so that document attrbute changes can be dealt collaboratively.
Step.jsonID(STEPNAME_SDA, SetDocAttrStep);
} catch (err) {
if (err.message !== `Duplicate use of step JSON ID ${STEPNAME_SDA}`)
if (err.message !== `Duplicate use of step JSON ID ${STEPNAME_SDA}`) {
// this means something else happened, cannot use this.
// otherwise it is already registered.
throw err;
}
}
return true;
}
Expand Down
Loading

0 comments on commit cd19829

Please sign in to comment.