Skip to content

Commit

Permalink
Split out code (#2)
Browse files Browse the repository at this point in the history
* Drafted mock of Obsidian editor.

* Implemented mock of MarkdownView and Editor, and got several example tests working.

* Fixed bug whereby blank lines were not being correctly identified, vs. lines with no leading indentation among indented lines.

* Improved cursor/selection location after toggleBlockquote, and continued adding tests.

* Got tests running again.

* Added <blockquote>-wrapped quote command.

* Removed extra console.log() call.
  • Loading branch information
jglev authored Aug 3, 2021
1 parent d0f8c54 commit e9ea8f4
Show file tree
Hide file tree
Showing 11 changed files with 550 additions and 152 deletions.
104 changes: 104 additions & 0 deletions __mocks__/obsidian.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Mock several classes from Obsidian, following
// https://github.com/obsidianmd/obsidian-api/blob/master/obsidian.d.ts:

class Notice {
msg: string

constructor(
msg: string
) {
this.msg = msg;
}
}

class Editor {
content: string[]
selectionStart: {line: number, ch: number}
selectionEnd: {line: number, ch: number}
selection: {line: number, ch: number}[]

constructor(
content: string[],
selectionStart: {line: number, ch: number},
selectionEnd: {line: number, ch: number},
) {
this.content = content;
this.selection = [selectionStart, selectionEnd];
}

getCursor() {
return this.selection[0];
}

getLine(line: number) {
return this.content[line];
}

getRange(
start: {line: number, ch: number},
end: {line: number, ch: number}
) {
const contentInRange = this.content.slice(start.line, end.line + 1);
contentInRange[0] = contentInRange[0].slice(start.ch);
contentInRange[contentInRange.length - 1] = contentInRange[contentInRange.length - 1].slice(0, end.ch);

return contentInRange.join('\n');
}

setSelection(
start: {line: number, ch: number},
end: {line: number, ch: number}
) {
this.selection = [start, end]
}

replaceSelection(text: string) {
this.content.splice(
this.selection[0].line,
this.selection[1].line - this.selection[0].line,
...(
this.content[this.selection[0].line].slice(0, this.selection[0].ch) +
text +
this.content[this.selection[1].line].slice(this.selection[1].ch)
).split('\n')
)
}

replaceRange(
text: string,
start: {line: number, ch: number},
end: {line: number, ch: number}
) {
this.content.splice(
start.line,
end.line - start.line + 1,
...(
this.content[start.line].slice(0, start.ch) +
text +
this.content[end.line].slice(end.ch)
).split('\n')
)
}
}

export class MarkdownView {
content: string[]
selectionStart: {line: number, ch: number}
selectionEnd: {line: number, ch: number}
editor: Editor

constructor(
content: string[],
selectionStart: {line: number, ch: number},
selectionEnd: {line: number, ch: number},
) {
this.editor = new Editor(
content,
selectionStart,
selectionEnd
);
}
}

export {};

19 changes: 19 additions & 0 deletions __tests__/mocks.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MarkdownView } from '../__mocks__/obsidian';

describe('Examining mocks', () => {
const view = new MarkdownView(
[
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'Sed venenatis lectus et leo viverra, ac viverra purus rutrum.',
'',
'Etiam semper massa ut est faucibus, eu luctus arcu porttitor.'
],
{line: 0, ch: 0},
{line: 0, ch: 0}
);

test('correctly creates a mock view', () => {
// console.log(`"${JSON.stringify(view)}`);
expect(JSON.stringify(view)).toEqual('{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":0},{"line":0,"ch":0}]}}');
});
});
23 changes: 23 additions & 0 deletions __tests__/paste-text.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MarkdownView } from '../__mocks__/obsidian';

import { pasteText } from '../src/paste-text';

// describe('Examining toggle-blockquote-at-current-indentation', () => {
// beforeAll(() => {
// const view = new MarkdownView(
// [
// 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
// 'Sed venenatis lectus et leo viverra, ac viverra purus rutrum.',
// '',
// 'Etiam semper massa ut est faucibus, eu luctus arcu porttitor.'
// ],
// {line: 0, ch: 0},
// {line: 0, ch: 0},
// {line: 0, ch: 0}
// );
// });

// test('Adds blockquote to single line', () => {
// return
// })
// });
163 changes: 163 additions & 0 deletions __tests__/toggle-quote.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import * as obsidian from "obsidian";

// Following https://stackoverflow.com/a/52366601,
// get Jest to understand that our mock of
// MarkdownView is quite different in its type
// definition from the actual obsidian MarkdownView
// (in that ours just implements some of the real
// class' methods):
const MarkdownView = <jest.Mock>obsidian.MarkdownView;

import { toggleQuote } from "../src/toggle-quote";

const defaultViewSettings = {
content: [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Sed venenatis lectus et leo viverra, ac viverra purus rutrum.",
"",
"Etiam semper massa ut est faucibus, eu luctus arcu porttitor.",
],
selectionStart: { line: 0, ch: 0 },
selectionEnd: { line: 0, ch: 0 },
};

const defaultPrefix = "> ";

describe("Examining toggle-blockquote-at-current-indentation", () => {
// beforeAll(() => {
// });

test("Adds and removes blockquote from single line with cursor at beginning of line", async () => {
const view = new MarkdownView(...Object.values(defaultViewSettings));

expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":0},{"line":0,"ch":0}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["> Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":2},{"line":0,"ch":2}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":0},{"line":0,"ch":0}]}}'
);
});

test("Adds and removes blockquote from single line with cursor at middle of line", async () => {
const view = new MarkdownView(
defaultViewSettings.content,
{ line: 0, ch: 5 },
{ line: 0, ch: 5 }
);

expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":5},{"line":0,"ch":5}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["> Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":7},{"line":0,"ch":7}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":5},{"line":0,"ch":5}]}}'
);
});

test("Adds and removes blockquote from single line that begins with whitespace with cursor at beginning of line", async () => {
const view = new MarkdownView(
[
' ' + defaultViewSettings.content[0],
...defaultViewSettings.content.slice(1)
],
{ line: 0, ch: 10 },
{ line: 0, ch: 10 }
);

expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":[" Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":10},{"line":0,"ch":10}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":[" > Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":12},{"line":0,"ch":12}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":[" Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":10},{"line":0,"ch":10}]}}'
);
});

test("Adds and removes blockquote from single line with single-line selection", async () => {
const view = new MarkdownView(
defaultViewSettings.content,
{ line: 0, ch: 5 },
{ line: 0, ch: 10 }
);

expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":5},{"line":0,"ch":10}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["> Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":7},{"line":0,"ch":12}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":5},{"line":0,"ch":10}]}}'
);
});

test("Adds and removes blockquote from single line that starts with whitespace, with selection that is entirely in the whitespace", async () => {
const view = new MarkdownView(
[
" " + defaultViewSettings.content[0],
...defaultViewSettings.content.slice(1),
],
{ line: 0, ch: 0 },
{ line: 0, ch: 4 }
);

expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":[" Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":0},{"line":0,"ch":4}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":[" > Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":0},{"line":0,"ch":4}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":[" Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":0},{"line":0,"ch":4}]}}'
);
});

test("Adds and removes blockquote from multiple lines with partial-line selection", async () => {
const view = new MarkdownView(
defaultViewSettings,
{ line: 0, ch: 5 },
{ line: 1, ch: 5 }
);

expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":5},{"line":1,"ch":5}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["> Lorem ipsum dolor sit amet, consectetur adipiscing elit.","> Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":7},{"line":1,"ch":7}]}}'
);

await toggleQuote(view, defaultPrefix);
expect(JSON.stringify(view)).toEqual(
'{"editor":{"content":["Lorem ipsum dolor sit amet, consectetur adipiscing elit.","Sed venenatis lectus et leo viverra, ac viverra purus rutrum.","","Etiam semper massa ut est faucibus, eu luctus arcu porttitor."],"selection":[{"line":0,"ch":5},{"line":1,"ch":7}]}}'
);
});
});
9 changes: 9 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
transform: {
"^.+\\.ts?$": "ts-jest",
},
testEnvironment: "jsdom",
// testRegex: "__tests__/.*\\.test?\\.ts$",
testMatch: ["**/__tests__/*.ts"],
moduleFileExtensions: ["ts", "js"],
};
Loading

0 comments on commit e9ea8f4

Please sign in to comment.