Browse Source

Add tests

simov 8 năm trước cách đây
mục cha
commit
81ff974a91
5 tập tin đã thay đổi với 773 bổ sung0 xóa
  1. 57 0
      test/advanced-defaults.js
  2. 191 0
      test/advanced-origins.js
  3. 80 0
      test/index.js
  4. 182 0
      test/popup-defaults.js
  5. 263 0
      test/popup-options.js

+ 57 - 0
test/advanced-defaults.js

@@ -0,0 +1,57 @@
+
+var t = require('assert')
+
+
+module.exports = ({advanced}) => {
+
+  it('access to file URLs', async () => {
+    t.strictEqual(
+      await advanced.evaluate(() =>
+        state.file
+      ),
+      true,
+      'state.file should be true'
+    )
+  })
+
+  it('header detection', async () => {
+    t.strictEqual(
+      await advanced.evaluate(() =>
+        state.header
+      ),
+      true,
+      'state.header should be true'
+    )
+  })
+
+  it('allowed origins', async () => {
+    t.deepStrictEqual(
+      await advanced.evaluate(() =>
+        state.origins
+      ),
+      {
+        'file://': '\\.(?:markdown|mdown|mkdn|md|mkd|mdwn|mdtxt|mdtext|text)(?:#.*|\\?.*)?$'
+      },
+      'state.origins should contain only the file:// origin'
+    )
+
+    t.deepStrictEqual(
+      await advanced.evaluate(() =>
+        state.origins
+      ),
+      await advanced.evaluate(() =>
+        Array.from(document.querySelectorAll('.m-list li'))
+          .reduce((obj, origin) => (
+            obj[
+              origin.querySelector('span:nth-of-type(1)').innerText.trim() +
+              '://' +
+              origin.querySelector('span:nth-of-type(2)').innerText.trim()
+            ] = origin.querySelector('.m-textfield input').value,
+            obj
+          ), {})
+      ),
+      'state.origins should be identical to dom origins'
+    )
+  })
+
+}

+ 191 - 0
test/advanced-origins.js

@@ -0,0 +1,191 @@
+
+var t = require('assert')
+
+
+module.exports = ({browser, advanced}) => {
+
+  describe('add origin', () => {
+    before(async () => {
+      // add
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+    })
+
+    it('localhost:3000', async () => {
+      t.equal(
+        await advanced.evaluate(() =>
+          document.querySelectorAll('.m-list li').length
+        ),
+        2,
+        'allowed origins count should be 2'
+      )
+      t.equal(
+        await advanced.evaluate(() =>
+          document.querySelector('.m-list li:nth-of-type(2) span:nth-of-type(1)').innerText
+        ),
+        'http',
+        'protocol should be http'
+      )
+      t.equal(
+        await advanced.evaluate(() =>
+          document.querySelector('.m-list li:nth-of-type(2) span:nth-of-type(2)').innerText
+        ),
+        'localhost:3000',
+        'hostname should be localhost:3000'
+      )
+    })
+  })
+
+  describe('disabled header detection + disabled path matching', () => {
+    var content
+
+    before(async () => {
+      // add origin
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+
+      // disable header detection
+      if (await advanced.evaluate(() => state.header)) {
+        await advanced.click('.m-switch')
+      }
+
+      // disable path matching
+      await advanced.evaluate(() => {
+        document.querySelector('.m-list li:nth-of-type(2) input').value = ''
+        document.querySelector('.m-list li:nth-of-type(2) input')
+          .dispatchEvent(new Event('keyup', {bubbles: true}))
+      })
+
+      // go to page serving markdown as text/markdown
+      content = await browser.newPage()
+      await content.goto('http://localhost:3000/correct-content-type')
+      await content.bringToFront()
+      await content.waitFor('pre')
+    })
+
+    it('text/markdown', async () => {
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('pre').innerText
+        ),
+        '**bold**',
+        'markdown should not be rendered'
+      )
+    })
+
+    after(async () => {
+      await content.close()
+    })
+  })
+
+  describe('enabled header detection + disabled path matching', () => {
+    var content
+
+    before(async () => {
+      // add origin
+      await advanced.bringToFront()
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+
+      // enable header detection
+      if (!await advanced.evaluate(() => state.header)) {
+        await advanced.click('.m-switch')
+      }
+
+      // disable path matching
+      await advanced.evaluate(() => {
+        document.querySelector('.m-list li:nth-of-type(2) input').value = ''
+        document.querySelector('.m-list li:nth-of-type(2) input')
+          .dispatchEvent(new Event('keyup', {bubbles: true}))
+      })
+
+      // open up new page
+      content = await browser.newPage()
+      await content.bringToFront()
+    })
+
+    it('text/markdown', async () => {
+      // go to page serving markdown as text/markdown
+      await content.goto('http://localhost:3000/correct-content-type')
+      await content.waitFor('#_html')
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html p strong').innerText
+        ),
+        'bold',
+        'markdown should be rendered'
+      )
+    })
+
+    it('text/x-markdown', async () => {
+      // go to page serving markdown as text/x-markdown
+      await content.goto('http://localhost:3000/correct-content-type-variation')
+      await content.waitFor('#_html')
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html p strong').innerText
+        ),
+        'bold',
+        'markdown should be rendered'
+      )
+    })
+
+    after(async () => {
+      await content.close()
+    })
+  })
+
+  describe('enabled header detection + enabled path matching', () => {
+    var content
+
+    before(async () => {
+      // add origin
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+
+      // enable header detection
+      if (!await advanced.evaluate(() => state.header)) {
+        await advanced.click('.m-switch')
+      }
+
+      // enable path matching
+      await advanced.evaluate(() => {
+        document.querySelector('.m-list li:nth-of-type(2) input').value = 'wrong-content-type'
+        document.querySelector('.m-list li:nth-of-type(2) input')
+          .dispatchEvent(new Event('keyup', {bubbles: true}))
+      })
+      // TODO: figure out why is this needed
+      await advanced.waitFor(600)
+
+      // open up new page
+      content = await browser.newPage()
+      await content.bringToFront()
+    })
+
+    it('text/plain', async () => {
+      // go to page serving markdown as text/plain
+      await content.goto('http://localhost:3000/wrong-content-type')
+      await content.waitFor('#_html')
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html p strong').innerText
+        ),
+        'bold',
+        'markdown should be rendered'
+      )
+    })
+
+    after(async () => {
+      await content.close()
+    })
+  })
+
+}

+ 80 - 0
test/index.js

@@ -0,0 +1,80 @@
+
+var path = require('path')
+var http = require('http')
+var puppeteer = require('puppeteer')
+
+var options = {
+  headless: false,
+  // slowMo: 300,
+  args: [
+    `--disable-extensions-except=${path.resolve(__dirname, '../')}`,
+    `--load-extension=${path.resolve(__dirname, '../')}`,
+  ],
+}
+
+var tests = [
+  'popup-defaults',
+  'advanced-defaults',
+  'advanced-origins',
+  'popup-options',
+]
+
+
+describe('markdown-viewer', () => {
+  var browser, server
+
+  it('test suite', async () => {
+    browser = await puppeteer.launch(options)
+
+    var page = await browser.newPage()
+    await page.goto('chrome://extensions')
+    await page.waitForSelector('.extension-id')
+    var id = await page.evaluate(() =>
+      document.querySelector('.extension-id').innerText.trim()
+    )
+
+    var popup = await browser.newPage()
+    await popup.goto(`chrome-extension://${id}/content/popup.html`)
+
+    var advanced = await browser.newPage()
+    await advanced.goto(`chrome-extension://${id}/content/options.html`)
+
+    await new Promise((resolve, reject) => {
+      server = http.createServer()
+      server.on('request', (req, res) => {
+        if (/wrong-content-type/.test(req.url)) {
+          res.setHeader('Content-Type', 'text/plain')
+          res.end('**bold**')
+        }
+        else if (/correct-content-type/.test(req.url)) {
+          res.setHeader('Content-Type', 'text/markdown')
+          res.end('**bold**')
+        }
+        else if (/correct-content-type-variation/.test(req.url)) {
+          res.setHeader('Content-Type', 'text/x-markdown')
+          res.end('**bold**')
+        }
+        else if (/compiler-options-marked/.test(req.url)) {
+          res.setHeader('Content-Type', 'text/x-markdown')
+          res.end('~~strikethrough~~')
+        }
+        else if (/compiler-options-remark/.test(req.url)) {
+          res.setHeader('Content-Type', 'text/x-markdown')
+          res.end('- [ ] task')
+        }
+      })
+      server.listen(3000, resolve)
+    })
+
+    tests.forEach((file) => {
+      describe(file, () => {
+        require(`./${file}.js`)({puppeteer, browser, popup, advanced})
+      })
+    })
+
+    after(async () => {
+      server.close()
+      await browser.close()
+    })
+  })
+})

+ 182 - 0
test/popup-defaults.js

@@ -0,0 +1,182 @@
+
+var t = require('assert')
+
+
+module.exports = ({popup}) => {
+
+  it('button - raw', async () => {
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.raw
+      ),
+      false,
+      'state.raw should equal false'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        document.querySelector('.m-button:first-child').innerText.toLowerCase()
+      ),
+      'markdown',
+      'button text should equal markdown'
+    )
+  })
+
+  it('tabs', async () => {
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.tab
+      ),
+      'theme',
+      'state.tab should equal theme'
+    )
+    t.deepStrictEqual(
+      await popup.evaluate(() =>
+        state.tabs
+      ),
+      await popup.evaluate(() =>
+        Array.from(document.querySelectorAll('.m-tabs a'))
+          .map((tab) => tab.innerText.trim().toLowerCase())
+      ),
+      'state.tabs should be identical to dom tabs'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        localStorage.getItem('tab')
+      ),
+      null,
+      'localStorage tab key should be null'
+    )
+  })
+
+  it('tab - theme', async () => {
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.theme
+      ),
+      'github',
+      'state.theme should equal github'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        document.querySelector('.m-panel:first-child')
+          .classList.contains('is-active')
+      ),
+      true,
+      'the first tab panel should be active'
+    )
+    t.deepStrictEqual(
+      await popup.evaluate(() =>
+        state.themes
+      ),
+      await popup.evaluate(() =>
+        Array.from(document.querySelectorAll('.m-panel:first-child select option'))
+          .map((option) => option.innerText)
+      ),
+      'state.themes should be identical to dom themes'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        document.querySelector('.m-panel:first-child select').selectedIndex
+      ),
+      0,
+      'dom select option should be 0'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.themes.length
+      ),
+      20,
+      'state.themes count should be 20'
+    )
+  })
+
+  it('tab - compiler', async () => {
+    await popup.click('.m-tabs a:nth-of-type(2)')
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.tab
+      ),
+      'compiler',
+      'state.tab should equal compiler'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        localStorage.getItem('compiler')
+      ),
+      null,
+      'localStorage compiler key should be null'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        document.querySelector('.m-panel:nth-of-type(2)')
+          .classList.contains('is-active')
+      ),
+      true,
+      'the second tab panel should be active'
+    )
+    t.deepStrictEqual(
+      await popup.evaluate(() =>
+        state.compilers
+      ),
+      await popup.evaluate(() =>
+        Array.from(document.querySelectorAll('.m-panel:nth-of-type(2) select option'))
+          .map((option) => option.innerText)
+      ),
+      'state.compilers should be identical to dom compilers'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        document.querySelector('.m-panel:first-child select').selectedIndex
+      ),
+      0,
+      'dom select option should be 0'
+    )
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.compilers.length
+      ),
+      2,
+      'state.compilers length should equal 2'
+    )
+    t.deepStrictEqual(
+      await popup.evaluate(() =>
+        Object.keys(state.options)
+        .filter((key) => typeof state.options[key] === 'boolean')
+        .reduce((obj, key) => (obj[key] = state.options[key], obj), {})
+      ),
+      await popup.evaluate(() =>
+        Array.from(document.querySelectorAll('.m-panel:nth-of-type(2) label'))
+          .reduce((all, option) => (
+            all[option.querySelector('span').innerText.trim()] =
+            option.classList.contains('is-checked'), all
+          ), {})
+      ),
+      'state.options should equal dom compiler options'
+    )
+  })
+
+  it('tab - content', async () => {
+    await popup.click('.m-tabs a:nth-of-type(3)')
+    t.strictEqual(
+      await popup.evaluate(() =>
+        state.tab
+      ),
+      'content',
+      'state.tab should equal content'
+    )
+    t.deepStrictEqual(
+      await popup.evaluate(() =>
+        state.content
+      ),
+      await popup.evaluate(() =>
+        Array.from(document.querySelectorAll('.m-panel:nth-of-type(3) label'))
+          .reduce((all, option) => (
+            all[option.querySelector('span').innerText.trim()] =
+            option.classList.contains('is-checked'), all
+          ), {})
+      ),
+      'state.content should equal dom content options'
+    )
+  })
+
+}

+ 263 - 0
test/popup-options.js

@@ -0,0 +1,263 @@
+
+var t = require('assert')
+
+
+module.exports = ({browser, popup, advanced}) => {
+
+  describe('set theme', () => {
+    var content
+
+    before(async () => {
+      // add origin
+      await advanced.bringToFront()
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+
+      // enable header detection
+      if (!await advanced.evaluate(() => state.header)) {
+        await advanced.click('.m-switch')
+      }
+
+      // select github-dark theme
+      await popup.bringToFront()
+      await popup.click('.m-tabs a:nth-of-type(1)')
+      await popup.select('.m-panel:nth-of-type(1) select', 'github-dark')
+
+      // go to page serving markdown as text/markdown
+      content = await browser.newPage()
+      await content.goto('http://localhost:3000/correct-content-type')
+      await content.bringToFront()
+      await content.waitFor('#_theme')
+    })
+
+    it('content', async () => {
+      t.strictEqual(
+        await content.evaluate(() =>
+          /github-dark\.css$/.test(
+            document.querySelector('#_theme').getAttribute('href')
+          )
+        ),
+        true,
+        'github-dark theme styles should be included'
+      )
+    })
+
+    it('popup', async () => {
+      // reaload popup
+      await popup.bringToFront()
+      await popup.reload()
+      await popup.waitFor('#popup')
+
+      t.equal(
+        await popup.evaluate(() =>
+          state.theme
+        ),
+        'github-dark',
+        'state.theme should equal github-dark'
+      )
+      t.equal(
+        await popup.evaluate(() =>
+          document.querySelectorAll('.m-panel:nth-of-type(1) select option')[
+            document.querySelector('.m-panel:nth-of-type(1) select').selectedIndex
+          ].innerText
+        ),
+        'github-dark',
+        'dom select option should be github-dark'
+      )
+    })
+
+    after(async () => {
+      await content.close()
+    })
+  })
+
+  describe('set compiler options - marked', () => {
+    var content
+
+    before(async () => {
+      // add origin
+      await advanced.bringToFront()
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+
+      // enable header detection
+      if (!await advanced.evaluate(() => state.header)) {
+        await advanced.click('.m-switch')
+      }
+
+      // popup
+      await popup.bringToFront()
+      // defaults button
+      await popup.click('button:nth-of-type(2)')
+      // compiler tab
+      await popup.click('.m-tabs a:nth-of-type(2)')
+
+      // go to page serving markdown as text/markdown
+      content = await browser.newPage()
+      await content.goto('http://localhost:3000/compiler-options-marked')
+      await content.bringToFront()
+      await content.waitFor('#_html')
+    })
+
+    it('gfm is enabled by default', async () => {
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html p del').innerText
+        ),
+        'strikethrough',
+        'gfm should be rendered'
+      )
+    })
+
+    it('gfm is disabled', async () => {
+      // disable gfm
+      await popup.bringToFront()
+      // gfm switch
+      await popup.click('.m-panel:nth-of-type(2) .m-switch:nth-of-type(2)')
+
+      // reload content
+      await content.bringToFront()
+      await content.reload()
+      await content.waitFor('#_html')
+
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html p').innerText
+        ),
+        '~~strikethrough~~',
+        'gfm should not be rendered'
+      )
+    })
+
+    it('popup state', async () => {
+      // reload popup
+      await popup.bringToFront()
+      await popup.reload()
+      await popup.waitFor('#popup')
+
+      t.strictEqual(
+        await popup.evaluate(() =>
+          state.options.gfm
+        ),
+        false,
+        'state.options.gfm should be false'
+      )
+      t.strictEqual(
+        await popup.evaluate(() =>
+          document.querySelector('.m-panel:nth-of-type(2) .m-switch:nth-of-type(2)')
+            .classList.contains('is-checked')
+        ),
+        false,
+        'dom gfm checkbox should be disabled'
+      )
+    })
+
+    after(async () => {
+      await content.close()
+    })
+  })
+
+  describe('set compiler options - remark', () => {
+    var content
+
+    before(async () => {
+      // add origin
+      await advanced.bringToFront()
+      await advanced.select('.m-select', 'http')
+      await advanced.type('[type=text]', 'localhost:3000')
+      await advanced.click('button')
+      await advanced.waitFor(() => document.querySelectorAll('.m-list li').length === 2)
+
+      // enable header detection
+      if (!await advanced.evaluate(() => state.header)) {
+        await advanced.click('.m-switch')
+      }
+
+      // popup
+      await popup.bringToFront()
+      // defaults button
+      await popup.click('button:nth-of-type(2)')
+      // compiler tab
+      await popup.click('.m-tabs a:nth-of-type(2)')
+
+      // go to page serving markdown as text/markdown
+      content = await browser.newPage()
+      await content.goto('http://localhost:3000/compiler-options-remark')
+      await content.bringToFront()
+      await content.waitFor('#_html')
+    })
+
+    it('marked should not render gfm task lists', async () => {
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html ul li').innerText
+        ),
+        '[ ] task',
+        'gfm task lists should not be rendered'
+      )
+    })
+
+    it('remark should render gfm task lists by default', async () => {
+      // select remark compiler
+      await popup.bringToFront()
+      await popup.select('.m-panel:nth-of-type(2) select', 'remark')
+
+      // reload content page
+      await content.bringToFront()
+      await content.reload()
+      await content.waitFor('#_html')
+
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html ul li').getAttribute('class')
+        ),
+        'task-list-item',
+        'dom li should have a class set'
+      )
+      t.strictEqual(
+        await content.evaluate(() =>
+          document.querySelector('#_html ul li [type=checkbox]')
+            .hasAttribute('disabled')
+        ),
+        true,
+        'dom li should contain checkbox in it'
+      )
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html ul li').innerText
+        ),
+        ' task',
+        'dom li should contain the task text'
+      )
+    })
+
+    it('remark disable gfm', async () => {
+      // disable gfm
+      await popup.bringToFront()
+      // gfm switch
+      await popup.click('.m-panel:nth-of-type(2) .m-switch:nth-of-type(4)')
+
+      // reload content
+      await content.bringToFront()
+      await content.reload()
+      await content.waitFor('#_html')
+
+      t.equal(
+        await content.evaluate(() =>
+          document.querySelector('#_html ul li').innerText
+        ),
+        '[ ] task',
+        'gfm task lists should not be rendered'
+      )
+    })
+
+    after(async () => {
+      await content.close()
+    })
+  })
+
+}