# markdown-editor **Repository Path**: pish7/markdown-editor ## Basic Information - **Project Name**: markdown-editor - **Description**: electron 实现的一个 markdown 编辑软件,使用了 vue.js、typescript 和 sass 等技术 - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2019-12-05 - **Last Updated**: 2021-05-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: Electron, Project ## README # markdown-editor ## 介绍 Electron 和 vue.js 创建的 Markdown 编辑器,编程语言使用 typescript 和 sass。 ## 创建项目 1. 远程仓库创建一个空项目 1. 本地使用 vue ui 命令创建一个 vue 项目,配置为使用 typescript,并用 eslint/prettier 格式化源码,样式使用 dart-sass。 1. 使用 vue add 命令添加 electron-builder 插件 - [vue-cli-plugin-electron-builder [npmjs]](https://www.npmjs.com/package/vue-cli-plugin-electron-builder) - [vue-cli-plugin-electron-builder [github]](https://nklayman.github.io/vue-cli-plugin-electron-builder/) 1. 执行以下命令初次运行软件 ```shell npm run electron:serve ``` 1. 使用 git init 初始化 git 仓库 1. 使用 git add 和 git commit 命令进行初次提交 1. 执行以下 git 命令将仓库同步到远程仓库 ```shell git remote add origin git@gitee.com:pish7/markdown-editor.git git push -u origin master ``` ## 初始化项目配置 - 修改 package.json,增加描述信息 ```json "author": { "name": "PISH", "email": "pish@163.com" }, "description": "Markdown 编辑器", ``` - 创建 .npmrc 文件,配置 npm,内容如下: ``` registry=https://registry.npm.taobao.org disturl=https://npm.taobao.org/dist ELECTRON_MIRROR=https://cdn.npm.taobao.org/dist/electron/ ``` - 创建 .prettierrc 文件,配置 Prettier,内容如下: ```json { "semi": false, "singleQuote": true, "printWidth": 80, "trailingComma": "es5" } ``` - 修改 .eslintrc.js 文件,添加以下规则: ```js { rules: { "prettier/prettier": "error", } } ``` - 执行以下命令来格式化整个项目的源码 ```shell npm run lint ``` ## 单元测试 本项目使用 jest 进行单元测试,对于 vue 项目,简单的方法是使用 @vue/cli-plugin-unit-jest,创建项目时可以选择包含该插件,也可以创建后再安装 ```shell vue add unit-jest ``` - [@vue/cli-plugin-unit-jest [github]](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-jest) ### 配置 jest - jest.config.js ```js module.exports = { preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel', verbose: true, collectCoverage: true, } ``` ### 配置测试命令 - package.json ```json "scripts": { "test:unit": "vue-cli-service test:unit --no-cache", "test": "npm run test:unit" }, ``` - --no-cache 是可选参数,表示不使用缓存。缓存对测试速度的影响很大,一般情况下不要使用此选项。如果要清除 jest 缓存,也可以使用以下命令 ```shell npx jest --clearCache ``` ### 编写测试文件 本项目中会用到一个 Note 类,下面针对该类编写一个示例性的测试文件 - tests/unit/Note.spec.ts ```ts import Note from '../../src/Note' describe('Note 对象初始化', () => { test('使用数字初始化 Note', () => { const time = Date.now() const note = new Note(2) expect(note.favorite).toBe(false) expect(note.title).toBe('New note 3') expect(note.content).toBe( '**Hi!** This notebook is using [markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) for formatting!' ) expect(typeof note.created).toBe('number') expect(time).toBeLessThanOrEqual(note.created) expect(note.created - time).toBeLessThan(1000) expect(String(note.created)).toEqual(note.id) }) test('使用对象初始化 Note', () => { const x = new Note(2) const note = new Note(x) expect(note.id).toBe(x.id) expect(note.content).toBe(x.content) expect(note.favorite).toBe(x.favorite) expect(note.created).toBe(x.created) expect(note.title).toBe(x.title) }) }) describe('Note 转换', () => { test('Markdown 转 HTML', () => { const note = new Note(2) note.content = '## Hello' const html = note.preview expect(html.trim()).toBe('

Hello

') }) }) describe('Note 统计', () => { test('行数', () => { const note = new Note(2) note.content = '## Hello\n### Hello' expect(note.linesCount).toBe(2) }) test('字数', () => { const note = new Note(2) note.content = '## Hello\n### Hello' expect(note.wordsCount).toBe(4) }) }) ``` 下面针对 NoteEdit 组件编写一个测试文件,同样地,这个文件只是一个示例性的测试文件,还需添加更多的测试 - src/components/\_\_test\_\_/NoteEdit.spec.ts ```ts import { shallowMount, createLocalVue } from '@vue/test-utils' import moment from 'moment' import Note from '@/Note' import NoteEdit from '../NoteEdit.vue' const localVue = createLocalVue() localVue.filter('date', (time: any) => moment(time).format('DD/MM/YY HH:mm')) describe('NoteEdit.vue', () => { const note = new Note(0) const wrapper = shallowMount(NoteEdit, { propsData: { note }, localVue, }) const el = wrapper.element it('笔记标题', () => { const input = el.querySelector('.toolbar input') as HTMLInputElement expect(input.value).toBe('New note 1') }) }) ``` 至此,不管是普通的 ts 文件还是 vue 组件,都可以成功地进行单元测试了 ### 执行测试 ```shell npm test ``` ## E2E 测试 Electron 有专门的 E2E 测试工具 spectron,不过由于前面已经安装过 vue-cli-plugin-electron-builder,这时不需要再单独安装 spectron 了。 ### 创建 E2E 测试配置文件 - jest.config.e2e.js ```js module.exports = { preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel', verbose: true, testMatch: ['/tests/e2e/**/*.spec.(js|jsx|ts|tsx)'], } ``` - 该测试配置将专门针对 tests/e2e 下的测试文件,e2e 测试文件存放于该目录下 ### 配置 E2E 测试命令 ```json "scripts": { "test:e2e": "vue-cli-service test:unit --config=jest.config.e2e.js", }, ``` ### 编写测试文件 - tests/e2e/index.spec.js ```js const { testWithSpectron } = require('vue-cli-plugin-electron-builder') let app, stopServe, client, win jest.setTimeout(50000) beforeAll(async () => { ;({ app: { client, browserWindow: win }, stopServe, } = await testWithSpectron()) }) afterAll(async () => { await stopServe() }) // 正常启动窗口 describe('窗口启动', function() { it('启动一个窗口', async () => { expect(await client.getWindowCount()).toBe(1) expect(await win.isMinimized()).toBe(false) expect(await win.isVisible()).toBe(true) const { width, height } = await win.getBounds() expect(width).toBeGreaterThan(0) expect(height).toBeGreaterThan(0) }) it('开发者工具已关闭', async () => { const devToolsAreOpen = await win.isDevToolsOpened() expect(devToolsAreOpen).toBe(false) }) it('窗口标题', async () => { const title = await client.getTitle() expect(title).toBe('electron-markdown-vue-ts-sass') }) }) // 正常显示定义的界面元素 describe('显示的界面元素', function() { it('添加笔记按钮', async () => { const hello = await client.getText('.toolbar button') expect(hello).toBe('add 添加笔记') }) }) ``` ### 执行测试 ```shell npm run test:e2e ``` ## 配置打包参数并打包 ### 创建项目配置文件 - vue.config.js ```js module.exports = { pluginOptions: { electronBuilder: { builderOptions: { appId: 'io.gitee.pish7.electron-markdown-vue-ts-sass', productName: 'electron-markdown-vue-ts-sass', win: { target: 'portable', icon: 'public/favicon.ico', extraFiles: ['./public/**/*'], }, nsis: { oneClick: false, allowToChangeInstallationDirectory: true, installerHeaderIcon: 'public/favicon.ico', }, }, }, }, } ``` - 图标需要更换为一个 256x256 的 ico 图标 - 创建窗口时需要对图标进行配置 {icon: 'public/favicon.ico'} ### 执行打包 ```shell npm run electron:build ```