Skip to content

Commit

Permalink
Create <Markdown> Component
Browse files Browse the repository at this point in the history
- Create `Markdown.vue` file in `src/components` directory

- Create `Markdown.spec.js` file in `test/components` directory

- Write unit tests for `<Editor>` component
  Ensure it has a name.
  Ensure it has correct props.
  Ensure it renders correct HTML for given markdown string.
  Ensure it sanitizes markdown string.

- Install marked
  ``` bash
  npm add marked
  ```

- Write minimal code required to pass all tests.

- Use `<Markdown>` component in `<App>` component
  Write unit test for `<App>` component.
    Ensure it renders `<Markdown>` component.
  Write minimal code required to pass all tests.

- Add CSS to `Markdown.vue`
  Start vue dev server. (`npm run dev`)
  Preview the `<Markdown>` component in browser.
  Write required style in style inspector.
  Move final styles to `Markdown.vue` file.
  • Loading branch information
znck committed Feb 1, 2018
1 parent 744e66b commit b003a16
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 2 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -5,6 +5,7 @@
"private": true,
"main": "src/index.js",
"dependencies": {
"marked": "^0.3.12",
"vue": "^2.5.13"
},
"devDependencies": {
Expand Down
35 changes: 33 additions & 2 deletions src/App.vue
@@ -1,17 +1,48 @@
<template>
<div class="app">
<Editor v-model="content" />
<div class="sep" />
<Markdown :content="content" />
</div>
</template>


<script>
import Editor from './components/Editor.vue'
import Markdown from './components/Markdown.vue'
export default {
name: 'MarkdownNotebook',
components: { Editor },
components: { Editor, Markdown },
data: () => ({
content: ''
})
}
</script>
</script>

<style>
html, body {
padding: 0;
margin: 0;
height: 100%;
font-size: 16px;
}
</style>


<style scoped>
.app {
display: flex;
flex-direction: row;
min-height: 100%;
}
.app > * {
flex: 1;
}
.sep {
flex: 0;
border: 1px solid #ccc;
margin: 0 15px;
}
</style>
29 changes: 29 additions & 0 deletions src/components/Markdown.vue
@@ -0,0 +1,29 @@
<template>
<div class="output" v-html="html" />
</template>


<script>
import marked from 'marked'
export default {
name: 'Markdown',
props: {
content: {
type: String,
required: true
}
},
computed: {
html() {
return marked(this.content, { sanitize: true })
}
}
}
</script>

<style scoped>
.output {
padding: 15px;
}
</style>

2 changes: 2 additions & 0 deletions test/App.spec.js
@@ -1,6 +1,7 @@
import { shallow } from '@vue/test-utils'
import App from '@/App.vue'
import Editor from '@/components/Editor.vue'
import Markdown from '@/components/Markdown.vue'

describe('<App>', () => {
describe('Component', () => {
Expand All @@ -12,6 +13,7 @@ describe('<App>', () => {
const wrapper = shallow(App)

expect(wrapper.contains(Editor)).toBeTruthy()
expect(wrapper.contains(Markdown)).toBeTruthy()
})
})
})
49 changes: 49 additions & 0 deletions test/components/Markdown.spec.js
@@ -0,0 +1,49 @@
import { shallow } from '@vue/test-utils'
import Markdown from '@/components/Markdown.vue'

describe('<Preview>', () => {
describe('Component', () => {
test('has name', () => {
expect(Markdown.name.length).toBeTruthy()
})

test('renders markdown', () => {
const content = `Time is ${new Date()}`
const wrapper = shallow(Markdown, {
propsData: { content: `# ${content}\n` }
})

wrapper.update()

expect(wrapper.element.querySelector('h1')).toBeTruthy()
expect(wrapper.element.textContent).toEqual(expect.stringContaining(content))
})

test('should sanitize markdown', () => {
const wrapper = shallow(Markdown, {
propsData: { content: `<div id="foo">Hello</div>\n` }
})

wrapper.update()

expect(wrapper.element.querySelector('#foo')).toBeFalsy()
expect(wrapper.element.textContent).toEqual(expect.stringContaining('<div id="foo">Hello</div>'))
})
})
describe('API', () => {
const wrapper = shallow(Markdown, { propsData: { content: '' } })
const props = wrapper.vm.$options.props

test('accepts content prop', () => {
expect(props.content).toBeTruthy()
})

test('content is string', () => {
expect(props.content.type).toEqual(String)
})

test('content is required', () => {
expect(props.content.required).toEqual(true)
})
})
})

0 comments on commit b003a16

Please sign in to comment.