diff --git a/packages/@vuepress/core/lib/node/__tests__/prepare/Page.spec.js b/packages/@vuepress/core/lib/node/__tests__/prepare/Page.spec.js index e176f6dd5f..41d159d425 100644 --- a/packages/@vuepress/core/lib/node/__tests__/prepare/Page.spec.js +++ b/packages/@vuepress/core/lib/node/__tests__/prepare/Page.spec.js @@ -7,54 +7,51 @@ const { readFile } = require('./util') -describe('Page', () => { - let app - let computed +let app +let computed - beforeAll(async () => { - app = new App() - await app.process() - computed = new app.ClientComputedMixinConstructor() - }) +beforeAll(async () => { + app = new App() + await app.process() + computed = new app.ClientComputedMixinConstructor() +}) - test('pure route', async () => { - const page = new Page({ path: '/' }, app) +async function setupPage (options, processOption = {}) { + const page = new Page(options, app) + await page.process({ computed, ...processOption }) + return page +} - expect(page.path).toBe('/') - expect(page.regularPath).toBe('/') - - await page.process({ computed }) +describe('pure route', () => { + test('should get pure route', async () => { + const page = await setupPage({ path: '/' }) expect(page.path).toBe('/') expect(page.regularPath).toBe('/') + expect(page.frontmatter).toEqual({}) }) - test('pure route - encodeURI', async () => { + test('should encode the path', async () => { const path = '/尤/' - const page = new Page({ path }, app) + const encodePath = encodeURI(path) + const page = await setupPage({ path }) - expect(page.path).toBe(encodeURI(path)) - expect(page.regularPath).toBe(encodeURI(path)) + expect(page.path).toBe(encodePath) + expect(page.regularPath).toBe(encodePath) }) - test('pure route - custom frontmatter', async () => { - const frontmatter = { title: 'alpha' } - const page = new Page({ + test('should be able to set custom frontmatter', async () => { + const frontmatter = { foo: 'alpha' } + const page = await setupPage({ path: '/', frontmatter - }, app) - expect(page.frontmatter).toBe(frontmatter) + }) + + expect(page.frontmatter.foo).toBe(frontmatter.foo) }) - test('pure route - enhancers', async () => { + test('should be able to use enhancers', async () => { const frontmatter = { title: 'alpha' } - const page = new Page({ - path: '/', - frontmatter - }, app) - - expect(page.frontmatter.title).toBe('alpha') - const enhancers = [ { name: 'plugin-a', @@ -63,91 +60,240 @@ describe('Page', () => { } } ] - await page.process({ computed, enhancers }) + const page = await setupPage({ path: '/', frontmatter }, { enhancers }) expect(page.frontmatter.title).toBe('beta') }) +}) + +describe('permalink', () => { + test('should be able to set permalink', async () => { + const page = await setupPage({ permalink: '/permalink' }) + + expect(page.path).toBe('/permalink') + expect(page.regularPath).toBe('/permalink') + }) + + test('should be able to set permalink from frontmatter', async () => { + const frontmatter = { permalink: '/permalink' } + const page = await setupPage({ path: '/', frontmatter }) + + expect(page.path).toBe('/permalink/') + expect(page.regularPath).toBe('/') + }) + + test('should be able to set permalink from global pattern', async () => { + const permalinkPattern = '/:year/:month/:day/:slug' + const { relative, filePath } = getDocument('2020-01-01-date.md') + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative, permalinkPattern }, { markdown }) + expect(page.path).toBe('/2020/01/01/date/') + expect(page.regularPath).toBe('/2020-01-01-date.html') + + const pageWithLocalePath = await setupPage( + { filePath, relative, permalinkPattern }, + { computed: { setPage () {}, $localePath: '/zh/' }, markdown } + ) + expect(pageWithLocalePath.path).toBe('/zh/2020/01/01/date/') + }) +}) - test('markdown page - pointing to a markdown file', async () => { +describe('markdown page', () => { + test('should be able to pointing to a markdown file', async () => { const { relative, filePath } = getDocument('README.md') - const page = new Page({ filePath, relative }, app) + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) expect(page._filePath).toBe(filePath) expect(page.regularPath).toBe('/') expect(page.path).toBe('/') expect(page.frontmatter).toEqual({}) - const markdown = getMarkdown() - await page.process({ computed, markdown }) + const content = await readFile(filePath) + + expect(page._content).toBe(content) + expect(page._strippedContent).toBe(content) + }) - expect(page.title).toBe('Home') + test('should be able add a page with explicit content', async () => { + const { filePath } = getDocument('README.md') const content = await readFile(filePath) + const markdown = getMarkdown() + const page = await setupPage({ content }, { markdown }) + expect(page._content).toBe(content) expect(page._strippedContent).toBe(content) }) - test('markdown page - pointing to a markdown file with frontmatter', async () => { + test('should work with frontmatter when pointing to a markdown file', async () => { const { relative, filePath } = getDocument('alpha.md') - const page = new Page({ filePath, relative }, app) + const title = 'VuePress Alpha' // from fixture + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) expect(page._filePath).toBe(filePath) expect(page.regularPath).toBe('/alpha.html') expect(page.path).toBe('/alpha.html') - expect(page.frontmatter).toEqual({}) + expect(page.frontmatter.title).toBe(title) + expect(page._content.startsWith('---')).toBe(true) + expect(page._strippedContent.startsWith('---')).toBe(false) + }) + test('should extract any content above as excerpt', async () => { + const { relative, filePath } = getDocument('excerpt.md') const markdown = getMarkdown() - await page.process({ computed, markdown }) + const page = await setupPage({ filePath, relative }, { markdown }) - expect(page.title).toBe(page.frontmatter.title) - expect(page._content.startsWith('---')).toBe(true) - expect(page._strippedContent.startsWith('---')).toBe(false) + expect(page.excerpt).toMatchSnapshot() }) - describe('enhance - ', () => { - let page - let enhancers - - beforeEach(() => { - page = new Page({ path: '/' }, app) - enhancers = [ - { - name: 'foo', - value: jest.fn() - }, - { - name: 'bar', - value: jest.fn() - } - ] - global.console.log = jest.fn() - }) + test('should extract level 2 and 3 headers by default', async () => { + const { relative, filePath } = getDocument('alpha.md') + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) - test('should loop over sync enhancers', async () => { - await page.enhance(enhancers) + expect(page.headers).toMatchSnapshot() + }) - return enhancers.map(enhancer => expect(enhancer.value).toHaveBeenCalled()) - }) + test('should extract headers by config', async () => { + const { relative, filePath } = getDocument('alpha.md') + const markdown = getMarkdown() + const extractHeaders = ['h1', 'h2'] + const page = await setupPage({ filePath, relative, extractHeaders }, { markdown }) - test('should loop over sync and async enhancers', async () => { - const mixedEnhancers = [...enhancers, { - name: 'blog', - value: jest.fn().mockResolvedValue({}) - }] - await page.enhance(mixedEnhancers) + expect(page.headers).toMatchSnapshot() + }) +}) - return mixedEnhancers.map(enhancer => expect(enhancer.value).toHaveBeenCalled()) - }) +describe('title', () => { + test('should be able to set title', async () => { + const title = 'VuePress' + const page = await setupPage({ path: '/', title }) + expect(page.title).toBe(title) + }) - test('should log and throw an error when enhancing fails', async () => { - const error = { errorMessage: 'this is an error message' } - const pluginName = 'error-plugin' + test('should set title from frontmatter', async () => { + const title = 'VuePress Alpha' // from fixture + const { relative, filePath } = getDocument('alpha.md') + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) + expect(page.title).toBe(title) + }) - await expect(page.enhance([{ - name: pluginName, - value: jest.fn().mockRejectedValue(error) - }])).rejects.toThrowError(`[${pluginName}] execute extendPageData failed.`) + test('should use first header in markdown to set title ', async () => { + const title = 'Home' // from fixture + const { relative, filePath } = getDocument('README.md') + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) + expect(page.title).toBe(title) + }) +}) - expect(console.log).toHaveBeenCalledWith(error) - }) +describe('enhancer', () => { + test('should loop over sync enhancers', async () => { + const page = await setupPage({ path: '/' }) + const enhancers = [ + { + name: 'foo', + value: jest.fn() + }, + { + name: 'foo', + value: jest.fn() + } + ] + await page.enhance(enhancers) + + return enhancers.map(enhancer => expect(enhancer.value).toHaveBeenCalled()) + }) + + test('should loop over sync and async enhancers', async () => { + const page = await setupPage({ path: '/' }) + const enhancers = [ + { + name: 'foo', + value: jest.fn() + }, + { + name: 'foo', + value: jest.fn() + } + ] + const mixedEnhancers = [...enhancers, { + name: 'blog', + value: jest.fn().mockResolvedValue({}) + }] + await page.enhance(mixedEnhancers) + + return mixedEnhancers.map(enhancer => expect(enhancer.value).toHaveBeenCalled()) + }) + + test('should log and throw an error when enhancing fails', async () => { + global.console.log = jest.fn() + const pluginName = 'error-plugin' + + const page = await setupPage({ path: '/' }) + const error = { errorMessage: 'this is an error message' } + + await expect(page.enhance([{ + name: pluginName, + value: jest.fn().mockRejectedValue(error) + }])).rejects.toThrowError(`[${pluginName}] execute extendPageData failed.`) + + expect(console.log).toHaveBeenCalledWith(error) }) }) + +describe('public api', () => { + test('dirname', async () => { + const dirname = 'docs' + const { relative, filePath } = getDocument('README.md') + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) + expect(page.dirname).toBe(dirname) + }) + + test('filename', async () => { + const filename = 'README' + const { relative, filePath } = getDocument(`${filename}.md`) + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) + expect(page.filename).toBe(filename) + }) + + test('slug', async () => { + const markdown = getMarkdown() + const dirname = 'docs' + const indexPageFixture = getDocument('README.md') + const indexPage = await setupPage( + { filePath: indexPageFixture.filePath, relative: indexPageFixture.relative }, { markdown } + ) + expect(indexPage.slug).toBe(dirname) + + const filename = 'alpha' + const pageFixture = getDocument(`${filename}.md`) + const page = await setupPage( + { filePath: pageFixture.filePath, relative: pageFixture.relative }, { markdown } + ) + expect(page.slug).toBe(filename) + }) + + test('strippedFilename', async () => { + const { relative, filePath } = getDocument('2020-01-01-date.md') + const markdown = getMarkdown() + const page = await setupPage({ filePath, relative }, { markdown }) + expect(page.strippedFilename).toBe('date') + }) + + test('date', async () => { + const frontmatter = { date: '2020-01-01' } + const dateInFrontmatterPage = await setupPage({ path: '/', frontmatter }) + expect(dateInFrontmatterPage.date).toBe('2020-01-01') + + const { relative, filePath } = getDocument('2020-01-01-date.md') + const markdown = getMarkdown() + const dateInPathPage = await setupPage({ filePath, relative }, { markdown }) + expect(dateInPathPage.date).toBe('2020-01-01') + }) +}) + diff --git a/packages/@vuepress/core/lib/node/__tests__/prepare/__snapshots__/Page.spec.js.snap b/packages/@vuepress/core/lib/node/__tests__/prepare/__snapshots__/Page.spec.js.snap new file mode 100644 index 0000000000..b3371deefa --- /dev/null +++ b/packages/@vuepress/core/lib/node/__tests__/prepare/__snapshots__/Page.spec.js.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`markdown page should extract any content above as excerpt 1`] = ` +

Excerpt

+

Blablabla...

+`; + +exports[`markdown page should extract headers by config 1`] = ` +Array [ + Object { + "level": 1, + "slug": "alpha", + "title": "Alpha", + }, + Object { + "level": 2, + "slug": "h2", + "title": "h2", + }, +] +`; + +exports[`markdown page should extract level 2 and 3 headers by default 1`] = ` +Array [ + Object { + "level": 2, + "slug": "h2", + "title": "h2", + }, + Object { + "level": 3, + "slug": "h3", + "title": "h3", + }, +] +`; diff --git a/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/2020-01-01-date.md b/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/2020-01-01-date.md new file mode 100644 index 0000000000..eef5ce9f78 --- /dev/null +++ b/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/2020-01-01-date.md @@ -0,0 +1 @@ +# Date diff --git a/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/alpha.md b/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/alpha.md index 67de3e0ace..b85c0a5769 100644 --- a/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/alpha.md +++ b/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/alpha.md @@ -3,3 +3,7 @@ title: VuePress Alpha --- # Alpha + +## h2 + +### h3 diff --git a/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/excerpt.md b/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/excerpt.md new file mode 100644 index 0000000000..2b1c8c7591 --- /dev/null +++ b/packages/@vuepress/core/lib/node/__tests__/prepare/fixtures/docs/excerpt.md @@ -0,0 +1,4 @@ +# Excerpt + +Blablabla... +