UNPKG

36.1 kBJavaScriptView Raw
1process.env.VUE_LOADER_TEST = true
2
3var path = require('path')
4var webpack = require('webpack')
5var MemoryFS = require('memory-fs')
6var jsdom = require('jsdom')
7var expect = require('chai').expect
8var rimraf = require('rimraf')
9var genId = require('vue-loader/lib/gen-id')
10var SourceMapConsumer = require('source-map').SourceMapConsumer
11var ExtractTextPlugin = require("extract-text-webpack-plugin")
12var compiler = require('vue-loader/lib/template-compiler')
13var normalizeNewline = require('normalize-newline')
14
15var vuxLoader = require('../src/index.js')
16var i18nParser = require('../libs/parse-i18n-function').parse
17const i18nParserForScript = require('../libs/replace-i18n-for-script').replace
18const getI18nBlock = require('../libs/get-i18n-block').get
19const getI18nBlockWithLocale = require('../libs/get-i18n-block').getWithLocale
20
21function getOptionsPlugin(config) {
22 const match = config.plugins.filter(one => {
23 return one.constructor.name === 'LoaderOptionsPlugin'
24 })
25 return match[0]
26}
27
28// var loaderPath = 'expose-loader?vueModule!' + path.resolve(__dirname, '../node_modules/vue-loader/index.js')
29var loaderPath = 'expose-loader?vueModule!' + path.resolve(__dirname, '../src/index.js') + '!vue-loader'
30var mfs = new MemoryFS()
31var globalConfig = {
32 output: {
33 path: '/',
34 filename: 'test.build.js'
35 },
36 module: {
37 rules: [
38 {
39 test: /\.vue$/,
40 loader: loaderPath
41 }
42 ]
43 }
44}
45
46function bundle(options, vuxOptions, cb) {
47 var vueOptions = options.vue
48 delete options.vue
49 var config = Object.assign(globalConfig, options)
50
51 // assign vue Options
52 if (vueOptions) {
53 config.plugins = (config.plugins || []).concat(new webpack.LoaderOptionsPlugin({
54 vue: vueOptions
55 }))
56 }
57 let basicVux = {
58 options: {
59 loaderString: loaderPath,
60 rewriteLoaderString: false,
61 isWebpack2: true,
62 isTest: true
63 }
64 }
65
66 if (vuxOptions.options) {
67 for (let i in vuxOptions.options) {
68 basicVux.options[i] = vuxOptions.options[i]
69 }
70 }
71
72 if (vuxOptions.plugins) {
73 basicVux.plugins = vuxOptions.plugins
74 }
75
76 config = vuxLoader.merge(config, basicVux)
77
78 var webpackCompiler = webpack(config)
79
80 webpackCompiler.outputFileSystem = mfs
81 webpackCompiler.run(function (err, stats) {
82 expect(err).to.be.null
83 if (stats.compilation.errors.length) {
84 stats.compilation.errors.forEach(function (err) {
85 console.error(err.message)
86 })
87 }
88 expect(stats.compilation.errors).to.be.empty
89 cb(mfs.readFileSync('/test.build.js').toString())
90 })
91}
92
93function test(options, vuxOptions, assert) {
94 bundle(options, vuxOptions, function (code) {
95 jsdom.env({
96 html: '<!DOCTYPE html><html><head></head><body></body></html>',
97 src: [code],
98 done: function (err, window) {
99 if (err) {
100 console.log(err[0].data.error.stack)
101 expect(err).to.be.null
102 }
103 assert(window, interopDefault(window.vueModule), window.vueModule)
104 }
105 })
106 })
107}
108
109function mockRender(options, data) {
110 return options.render.call(Object.assign({
111 _v(val) {
112 return val
113 },
114 _self: {},
115 $createElement(tag, data, children) {
116 if (Array.isArray(data)) {
117 children = data
118 data = null
119 }
120 return {
121 tag: tag,
122 data: data,
123 children: children
124 }
125 },
126 _m(index) {
127 return options.staticRenderFns[index].call(this)
128 },
129 _s(str) {
130 return String(str)
131 }
132 }, data))
133}
134
135function interopDefault(module) {
136 return module ? module.__esModule ? module.default : module : module
137}
138
139var parse = require('../src/libs/import-parser')
140
141const str = parse(`<script>
142import {
143 Group
144 } from 'vux';
145
146`, function (opts) {
147 // console.log(opts)
148})
149
150var themeParse = require('../src/libs/get-less-variables')
151
152var commomMapper = function (opts) {
153 components = opts.components.map(function (one) {
154 return one.newName
155 })
156 return `import { ${components.join(', ')} } from 'vux'`
157}
158
159var vuxMapper = function (opts) {
160 let str = ''
161 opts.components.forEach(function (one) {
162 if (one.originalName === 'AlertPlugin') {
163 str += `import ${one.newName} from 'vux/src/plugins/Alert'\n`
164 } else if (one.originalName === 'ToastPlugin') {
165 str += `import ${one.newName} from 'vux/src/plugins/Toast'\n`
166 }
167 })
168 return str
169}
170
171describe('vux-loader', function () {
172
173 describe('get i18n block', function () {
174
175 it('basic', function () {
176 const rs = getI18nBlock(`sfdsf<i18n>
177a:
178 en: en_a
179 zh-CN: zh-CN_a
180</i18n>sdfdsf`)
181 expect(rs.a.en).to.equal('en_a')
182 })
183
184 it('return empty object for wrong format', function () {
185 const rs = getI18nBlock(`sfdsf<i18n>
186a:
187en: en_a
188 zh-CN: zh-CN_a
189</i18n>sdfdsf`)
190 expect(JSON.stringify(rs)).to.equal('{}')
191 })
192
193
194 it('with locale', function () {
195 const rs = getI18nBlockWithLocale({code: `sfdsf<i18n>
196a:
197 en: en_a
198 zh-CN: zh-CN_a
199</i18n>sdfdsf`,
200locale: 'en'})
201 expect(rs.a).to.equal('en_a')
202 })
203
204 })
205
206 describe('parse i18n for js', function () {
207 const rs = i18nParserForScript(`this.$t('a')`, {})
208 expect(rs).to.equal(`'a'`)
209 })
210
211 describe('parse i18n', function () {
212
213 const map = {
214 a: 'A',
215 b: 'B',
216 c: 'C',
217 d: 'D'
218 }
219
220 const source1 = `<div :a="$t('a')">
221<p :c="d" e="f" g="hh">
222<span :options="['a', 'b', 'c', 'd']"></span>
223<span :obj="{a:'aa',b:'bb', c:$t('ee')}"></span>
224<span v-html="$t('sdfsdf')"></span>
225<span v-html="$t('sdfsdf') + $t('sfowewf') + $t('92fdf')"></span>
226{{ $t('dd') }}
227</p>
228</div>`
229
230 const cases = [{
231 raw: `<div :a="$t('a')"></div>`,
232 rs: `<div :a="'A'"></div>`
233}, {
234 raw: `<div :a="$t('x')"></div>`,
235 rs: `<div :a="'x'"></div>`
236}, {
237 raw: `<div :a='$t("a")'></div>`,
238 rs: `<div :a="'A'"></div>`
239}, {
240 raw: `<div v-html="$t('a')"></div>`,
241 rs: `<div v-html="'A'"></div>`
242}, {
243 raw: `<div :a="$t('a') + $t('b')"></div>`,
244 rs: `<div :a="'A' + 'B'"></div>`
245}, {
246 raw: `<div :a="$t('a') + 'B'"></div>`,
247 rs: `<div :a="'A' + 'B'"></div>`
248}, {
249 raw: `<div :a="$t('a') * 'B'"></div>`,
250 rs: `<div :a="'A' * 'B'"></div>`
251}, {
252 raw: `<div :a="{c: $t('a')}"></div>`,
253 rs: `<div :a="{ c: 'A' }"></div>`
254}, {
255 raw: `<div :a="{c: $t('a') + 'B'}"></div>`,
256 rs: `<div :a="{ c: 'A' + 'B' }"></div>`
257}, {
258 raw: `<div :a="{c: $t('a') + 'B', b: 'C' + $t('b')}"></div>`,
259 rs: `<div :a="{
260c: 'A' + 'B',
261b: 'C' + 'B' }"></div>`
262}, {
263 raw: `<div :a="[$t('a')]"></div>`,
264 rs: `<div :a="['A']"></div>`
265}, {
266 raw: `<div :a="[$t('a'),$t('b')]"></div>`,
267 rs: `<div :a="[
268'A',
269'B' ]"></div>`
270}, {
271 raw: `xx {{ $t('a') }}`,
272 rs: `xx A`
273}, {
274 raw: `xx {{ $t('a') }} {{$t('b')}}`,
275 rs: `xx A B`
276}, {
277 raw: `xx {{ $t('a') }} {{ $t('dfsf' + 'dsfdsf') }}`,
278 rs: `xx A {{ $t('dfsf' + 'dsfdsf') }}`
279}, {
280 raw: `xx {{ $tt('a') }}`,
281 rs: `xx {{ $tt('a') }}`
282}]
283
284 cases.forEach((one, index) => {
285 it(`test ${index + 1}`, function () {
286 const rs = i18nParser(one.raw, map)
287 expect(rs === one.rs).to.equal(true)
288 })
289
290 })
291
292 })
293
294 describe('parse virtual component', function () {
295 const parse = require('../src/libs/parse-virtual-component')
296 it('basic', function () {
297 const source = `<x-icon type="arrow-up-b" size="10" v-if="0 == 0"></x-icon>`
298 const processed = parse(source, 'x-icon', function (query, a) {
299 return '<svg ' + query.stringList + '></svg>'
300 })
301 expect(processed).to.equal('<svg type="arrow-up-b" size="10" v-if="0 == 0"></svg>')
302 })
303
304 it('basic', function () {
305 const source = `<x-icon type="arrow-up-b" size="10" v-if="0 == 0"/>`
306 const processed = parse(source, 'x-icon', function (query, a) {
307 return '<svg ' + query.stringList + '></svg>'
308 })
309 expect(processed).to.equal('<svg type="arrow-up-b" size="10" v-if="0 == 0"></svg>')
310 })
311
312 it('basic', function () {
313 const source = `<x-icon
314 type="arrow-up-b" size="10"
315 v-if="0 == 0"/>`
316 const processed = parse(source, 'x-icon', function (query, a) {
317 return '<svg ' + query.stringList + '></svg>'
318 })
319 expect(processed).to.equal('<svg type="arrow-up-b" size="10" v-if="0 == 0"></svg>')
320 })
321
322 it('basic', function () {
323 const source = `<x-icon type="ios-ionic-outline" size="30"/>
324 <x-icon type="ios-ionic-outline" size="30"></x-icon>`
325 const processed = parse(source, 'x-icon', function (query, a) {
326 return '<svg ' + query.stringList + '></svg>'
327 })
328 expect(processed).to.equal(`<svg type="ios-ionic-outline" size="30"></svg>
329 <svg type="ios-ionic-outline" size="30"></svg>`)
330 })
331 })
332
333 describe('parse virtual component with break line', function () {
334 const parse = require('../src/libs/parse-virtual-component')
335 it('basic', function () {
336 const source = `<x-icon a="b"
337 type="arrow-up-b"
338 size="10"
339 v-if="0 == 0"></x-icon>`
340 const processed = parse(source, 'x-icon', function (query, a) {
341 return '<svg ' + query.stringList + '></svg>'
342 })
343 expect(processed).to.equal('<svg a="b" type="arrow-up-b" size="10" v-if="0 == 0"></svg>')
344 })
345 })
346
347 describe('parse virtual component', function () {
348 const parse = require('../src/libs/parse-virtual-component')
349 it('basic', function () {
350 const source = `<x-icon a="b" c="d" class="e f" slot="icon"></x-icon>`
351 const processed = parse(source, 'x-icon', function (query, a) {
352 return '<svg ' + query.stringList + '></svg>'
353 })
354 expect(processed).to.equal('<svg a="b" c="d" class="e f" slot="icon"></svg>')
355 })
356 })
357
358 describe('parse virtual component with click event', function () {
359 const parse = require('../src/libs/parse-virtual-component')
360 it('basic', function () {
361 const source = `<x-icon a="b" c="d" class="e f" slot="icon" @click.native="handler"></x-icon>`
362 const processed = parse(source, 'x-icon', function (query, a) {
363 return '<svg ' + query.stringList + '></svg>'
364 })
365 expect(processed).to.equal('<svg a="b" c="d" class="e f" slot="icon" @click="handler"></svg>')
366 })
367 })
368
369 describe('lib:get theme variables', function () {
370 it('basic', function () {
371 const rs = themeParse(path.resolve(__dirname, './vux-fixtures/less-theme-001.less'))
372 expect(rs.a).to.equal('b')
373 })
374
375 it('ignore comments', function () {
376 const rs = themeParse(path.resolve(__dirname, './vux-fixtures/less-theme-002.less'))
377 expect(rs.a).to.equal('b')
378 expect(rs.c).to.equal('d')
379 expect(rs.d).to.equal('e')
380 expect(rs.f).to.equal('g')
381 })
382
383 it('import files', function () {
384 const rs = themeParse(path.resolve(__dirname, './vux-fixtures/less-theme-import.less'))
385 expect(rs.x).to.equal('x')
386 expect(rs.y).to.equal('z')
387 })
388 })
389
390 describe('lib:import-parser', function () {
391
392 let tests = [{
393 title: 'basic',
394 string: `import {A,B} from 'vux'`,
395 rs: ['A', 'B']
396 }, {
397 title: 'basic',
398 string: `import {A,B,} from 'vux'`,
399 rs: ['A', 'B']
400 }, {
401 title: 'without space',
402 string: `import{A,B} from 'vux'`,
403 rs: ['A', 'B']
404 }, {
405 title: 'without space 2',
406 string: `import {A,B}from 'vux'`,
407 rs: ['A', 'B']
408 }, {
409 title: 'without space 3',
410 string: `import{A,B}from 'vux'`,
411 rs: ['A', 'B']
412 }, {
413 title: 'do not parse comments',
414 string: `// import {A,B} from 'vux'
415import { C, D} from 'vux'`,
416 rs: `\nimport { C, D } from 'vux'`
417 }, {
418 title: 'use as',
419 string: `import {A,B as C} from 'vux'`,
420 rs: ['A', 'C']
421 }, {
422 title: 'double quote',
423 string: `import {A,B} from "vux"`,
424 rs: ['A', 'B']
425 }, {
426 title: 'multi line and single quote',
427 string: `import { A,
428B } from 'vux'`,
429 rs: ['A', 'B']
430 }, {
431 title: 'multi line and double quote',
432 string: `import { A,
433B } from "vux"`,
434 rs: ['A', 'B']
435 }, {
436 title: 'no match',
437 string: `import {A,B} from 'vvv'`,
438 rs: `import {A,B} from 'vvv'`
439 }, {
440 title: 'more codes',
441 string: `import C from 'XY'
442import { D } from 'ZW'
443import {A,B} from 'vvv'
444import { C } from 'vux'`,
445 rs: `import C from 'XY'
446import { D } from 'ZW'
447import {A,B} from 'vvv'
448import { C } from 'vux'`
449 }, {
450 title: 'vux test2',
451 string: `import {Group,Cell} from 'vux'
452import value2name from 'vux/src/filters/value2name'`,
453 rs: `import { Group, Cell } from 'vux'
454import value2name from 'vux/src/filters/value2name'`
455}, {
456 title: 'vux test3',
457 string: `import {Group,
458Cell} from 'vux'
459import value2name from 'vux/src/filters/value2name'`,
460 rs: `import { Group, Cell } from 'vux'
461import value2name from 'vux/src/filters/value2name'`
462}, {
463 title: 'vux test4',
464 string: `import { M1, M2 } from 'vux'
465import { mapMutations, mapState } from 'vuex'
466import { Group, Cell } from 'vux'
467import { Group1, Cell1 } from 'vux'
468import value2name from 'vux/src/filters/value2name'`,
469 rs: `import { M1, M2 } from 'vux'
470import { mapMutations, mapState } from 'vuex'
471import { Group, Cell } from 'vux'
472import { Group1, Cell1 } from 'vux'
473import value2name from 'vux/src/filters/value2name'`
474}, {
475 title: 'vux test5',
476 string: `import {
477XX,
478YY} from 'vux'`,
479 rs: `import { XX, YY } from 'vux'`
480}, {
481 title: 'vux test6',
482 string: `/**/
483import {Divider } from 'vux'`,
484 rs: `/**/
485import { Divider } from 'vux'`
486}]
487
488 tests.forEach(function (one) {
489 it(one.title, function () {
490 const rs = parse(one.string, commomMapper)
491 if (typeof one.rs === 'string') {
492 expect(rs).to.equal(one.rs)
493 } else {
494 expect(rs).to.equal(`import { ${one.rs.join(', ')} } from 'vux'`)
495 }
496 })
497 })
498
499 it('vux test', function () {
500 const rs = parse(`import {AlertPlugin, ToastPlugin} from 'vux'`, vuxMapper)
501 expect(rs).to.equal(`import AlertPlugin from 'vux/src/plugins/Alert'
502import ToastPlugin from 'vux/src/plugins/Toast'
503`)
504 })
505
506 it('vux test7', function () {
507 const rs = parse(`import {AlertPlugin, ToastPlugin} from 'vux'
508// import { AlertPlugin } from 'vux'`, vuxMapper)
509 expect(rs).to.equal(`import AlertPlugin from 'vux/src/plugins/Alert'
510import ToastPlugin from 'vux/src/plugins/Toast'
511
512`)
513 })
514
515 it('issue #1579 (1)', function () {
516 const rs = parse(`import {
517 AlertPlugin,
518 ToastPlugin
519} from 'vux';`, vuxMapper)
520 expect(rs).to.equal(`import AlertPlugin from 'vux/src/plugins/Alert'
521import ToastPlugin from 'vux/src/plugins/Toast'
522`)
523 })
524
525 it('issue #1579 (2)', function () {
526 const rs = parse(`import {AlertPlugin,
527 ToastPlugin
528} from 'vux'`, vuxMapper)
529 expect(rs).to.equal(`import AlertPlugin from 'vux/src/plugins/Alert'
530import ToastPlugin from 'vux/src/plugins/Toast'
531`)
532 })
533
534 })
535
536 describe('plugin:less-theme', function () {
537
538 it('basic', function (done) {
539 test({
540 entry: './test/vux-fixtures/less-theme-basic.vue'
541 }, {
542 plugins: [{
543 name: 'less-theme',
544 path: './test/vux-fixtures/less-theme-basic.less'
545 }]
546 }, function (window, module, rawModule) {
547 var vnode = mockRender(module, {
548 msg: 'hi'
549 })
550 expect(vnode.tag).to.equal('p')
551
552 var styles = window.document.querySelectorAll('style')
553 expect(styles[0].textContent).to.contain('\n.p {\n color: red;\n}\n')
554
555 done()
556 })
557 })
558
559 })
560
561 describe('plugin:style-parser', function () {
562
563 it('basic', function (done) {
564 test({
565 entry: './test/vux-fixtures/style-parser-basic.vue'
566 }, {
567 plugins: [{
568 name: 'less-theme',
569 path: './test/vux-fixtures/less-theme-basic.less'
570 }, {
571 name: 'style-parser',
572 fn: function (source) {
573 return source.replace('@theme-p-color', 'yellow')
574 }
575 }]
576 }, function (window, module, rawModule) {
577 var vnode = mockRender(module, {
578 msg: 'hi'
579 })
580 expect(vnode.tag).to.equal('p')
581
582 var styles = window.document.querySelectorAll('style')
583 expect(styles[0].textContent).to.contain('\n.p {\n color: yellow;\n}\n')
584
585 done()
586 })
587 })
588
589 })
590
591 describe('plugin:template-feature-switch', function () {
592
593 it('basic', function (done) {
594 test({
595 entry: './test/vux-fixtures/template-feature-switch-basic.vue'
596 }, {
597 plugins: [{
598 name: 'template-feature-switch',
599 features: {
600 FEATURE1: true,
601 FEATURE2: false
602 }
603 }]
604 }, function (window, module, rawModule) {
605 var vnode = mockRender(module, {
606 msg: 'hi'
607 })
608
609 expect(vnode.tag).to.equal('div')
610 expect(vnode.children[0].indexOf('ON FEATURE1') > -1).to.equal(true)
611 expect(vnode.children[0].indexOf('OFF FEATURE2') > -1).to.equal(true)
612 done()
613 })
614 })
615
616 })
617
618 describe('one instance', function () {
619 it('should throw', function () {
620 const webpackConfig = {
621 plugins: []
622 }
623 const merge = function () {
624 return vuxLoader.merge(webpackConfig, {
625 options: {
626 env: 'env1'
627 },
628 plugins: [{
629 name: 'test1'
630 }, {
631 name: 'test1'
632 }]
633 })
634 }
635 expect(merge).to.throw(/only one instance is allowed/)
636 })
637 })
638
639 describe('merge multi times', function () {
640 it('should merge options', function () {
641 const webpackConfig = {
642 plugins: []
643 }
644 const config1 = vuxLoader.merge(webpackConfig, {
645 options: {
646 env: 'env1'
647 }
648 })
649
650 expect(getOptionsPlugin(config1).options.vux.options.env).to.equal('env1')
651
652 const config2 = vuxLoader.merge(config1, {
653 options: {
654 env: 'env2'
655 }
656 })
657
658 expect(getOptionsPlugin(config2).options.vux.options.env).to.equal('env2')
659 })
660
661 it('should merge plugins with the same name', function () {
662 const webpackConfig = {}
663 const config1 = vuxLoader.merge(webpackConfig, {
664 plugins: [{
665 name: 'test1',
666 arg: 1
667 }]
668 })
669
670 expect(getOptionsPlugin(config1).options.vux.plugins.length).to.equal(1)
671 expect(getOptionsPlugin(config1).options.vux.plugins[0].arg).to.equal(1)
672
673 const config2 = vuxLoader.merge(config1, {
674 plugins: [{
675 name: 'test1',
676 arg: 2
677 }]
678 })
679
680 expect(getOptionsPlugin(config1).options.vux.plugins.length).to.equal(1)
681 expect(getOptionsPlugin(config1).options.vux.plugins[0].arg).to.equal(2)
682
683 })
684
685 it('should delete plugin when env is change', function () {
686 const webpackConfig = {}
687 const config1 = vuxLoader.merge(webpackConfig, {
688 options: {
689 env: 'env1'
690 },
691 plugins: [{
692 name: 'test1',
693 arg: 1,
694 envs: ['env1']
695 }]
696 })
697
698 expect(config1.plugins[0].options.vux.plugins.length).to.equal(1)
699
700 const config2 = vuxLoader.merge(config1, {
701 options: {
702 env: 'env2'
703 }
704 })
705
706 expect(getOptionsPlugin(config1).options.vux.plugins.length).to.equal(0)
707
708 })
709
710 it('should merge plugins', function () {
711 const webpackConfig = {}
712 const config1 = vuxLoader.merge(webpackConfig, {
713 options: {
714 env: 'env1'
715 },
716 plugins: [{
717 name: 'test1',
718 arg: 1,
719 envs: ['env1']
720 }]
721 })
722
723 expect(getOptionsPlugin(config1).options.vux.allPlugins.length).to.equal(1)
724 expect(getOptionsPlugin(config1).options.vux.plugins.length).to.equal(1)
725
726 const config2 = vuxLoader.merge(config1, {
727 plugins: [{
728 name: 'test2'
729 }]
730 })
731
732 expect(getOptionsPlugin(config2).options.vux.allPlugins.length).to.equal(2)
733 expect(getOptionsPlugin(config2).options.vux.plugins.length).to.equal(2)
734
735 const config3 = vuxLoader.merge(config2, {
736 plugins: [{
737 name: 'test3',
738 envs: ['env3']
739 }]
740 })
741
742 expect(getOptionsPlugin(config3).options.vux.allPlugins.length).to.equal(3)
743 expect(getOptionsPlugin(config3).options.vux.plugins.length).to.equal(2)
744
745 })
746 })
747
748 describe('plugin:script-parser', function () {
749
750 it('fn function should work', function (done) {
751 test({
752 entry: './test/vux-fixtures/script-parser-fn.vue'
753 }, {
754 plugins: [{
755 name: 'script-parser',
756 fn: function (source) {
757 return source.replace('AAAA', 'BBBB')
758 }
759 }]
760 }, function (window, module, rawModule) {
761 var vnode = mockRender(module, {
762 msg: 'hi'
763 })
764 expect(vnode.tag).to.equal('p')
765 expect(module.data().msg).to.equal('BBBB')
766 done()
767 })
768 })
769
770 it('fn function should not work with env', function (done) {
771 test({
772 entry: './test/vux-fixtures/script-parser-fn.vue'
773 }, {
774 options: {
775 env: 'test'
776 },
777 plugins: [{
778 name: 'script-parser',
779 envs: ['production'],
780 fn: function (source) {
781 return source.replace('AAAA', 'BBBB')
782 }
783 }]
784 }, function (window, module, rawModule) {
785 var vnode = mockRender(module, {
786 msg: 'hi'
787 })
788 expect(vnode.tag).to.equal('p')
789 expect(module.data().msg).to.equal('AAAA')
790 done()
791 })
792 })
793 })
794
795 describe('plugin:template-parser', function () {
796
797 it('fn function should work', function (done) {
798 test({
799 entry: './test/vux-fixtures/template-parser-fn.vue'
800 }, {
801 plugins: [{
802 name: 'template-parser',
803 fn: function (source) {
804 return source.replace('我们没有底线', '我是有底线的')
805 }
806 }]
807 }, function (window, module, rawModule) {
808 var vnode = mockRender(module, {
809 msg: 'hi'
810 })
811 expect(vnode.tag).to.equal('p')
812 expect(vnode.children[0]).to.equal('我是有底线的')
813 done()
814 })
815 })
816
817 it('replaceList param should work', function (done) {
818 test({
819 entry: './test/vux-fixtures/template-parser-fn.vue'
820 }, {
821 plugins: [{
822 name: 'template-parser',
823 replaceList: [{
824 test: /我们没有/,
825 replaceString: ''
826 }, {
827 test: /底线/,
828 replaceString: '底线是什么'
829 }]
830 }]
831 }, function (window, module, rawModule) {
832 var vnode = mockRender(module, {
833 msg: 'hi'
834 })
835 expect(vnode.tag).to.equal('p')
836 expect(vnode.children[0]).to.equal('底线是什么')
837 done()
838 })
839 })
840
841 })
842})
843
844/**
845
846describe.skip('vue-loader', function () {
847 it('basic', function (done) {
848 test({
849 entry: './test/fixtures/basic.vue'
850 }, function (window, module, rawModule) {
851 var vnode = mockRender(module, {
852 msg: 'hi'
853 })
854 // <h2 class="red">{{msg}}</h2>
855 expect(vnode.tag).to.equal('h2')
856 expect(vnode.data.staticClass).to.equal('red')
857 expect(vnode.children[0]).to.equal('hi')
858
859 expect(module.data().msg).to.contain('Hello from Component A!')
860 var style = window.document.querySelector('style').textContent
861 style = normalizeNewline(style)
862 expect(style).to.contain('comp-a h2 {\n color: #f00;\n}')
863 done()
864 })
865 })
866
867 it('expose filename', function (done) {
868 test({
869 entry: './test/fixtures/basic.vue'
870 }, function (window, module, rawModule) {
871 expect(module.__file).to.equal(path.resolve(__dirname, './fixtures/basic.vue'))
872 done()
873 })
874 })
875
876 it('pre-processors', function (done) {
877 test({
878 entry: './test/fixtures/pre.vue'
879 }, function (window, module) {
880 var vnode = mockRender(module)
881 // div
882 // h1 This is the app
883 // comp-a
884 // comp-b
885 expect(vnode.children[0].tag).to.equal('h1')
886 expect(vnode.children[1].tag).to.equal('comp-a')
887 expect(vnode.children[2].tag).to.equal('comp-b')
888
889 expect(module.data().msg).to.contain('Hello from coffee!')
890 var style = window.document.querySelector('style').textContent
891 expect(style).to.contain('body {\n font: 100% Helvetica, sans-serif;\n color: #999;\n}')
892 done()
893 })
894 })
895
896 it('scoped style', function (done) {
897 test({
898 entry: './test/fixtures/scoped-css.vue'
899 }, function (window, module) {
900 var id = 'data-v-' + genId(require.resolve('./fixtures/scoped-css.vue'))
901 expect(module._scopeId).to.equal(id)
902
903 var vnode = mockRender(module, {
904 ok: true
905 })
906 // <div>
907 // <div><h1>hi</h1></div>
908 // <p class="abc def">hi</p>
909 // <template v-if="ok"><p class="test">yo</p></template>
910 // <svg><template><p></p></template></svg>
911 // </div>
912 expect(vnode.children[0].tag).to.equal('div')
913 expect(vnode.children[1]).to.equal(' ')
914 expect(vnode.children[2].tag).to.equal('p')
915 expect(vnode.children[2].data.staticClass).to.equal('abc def')
916 expect(vnode.children[4][0].tag).to.equal('p')
917 expect(vnode.children[4][0].data.staticClass).to.equal('test')
918
919 var style = window.document.querySelector('style').textContent
920 style = normalizeNewline(style)
921 expect(style).to.contain('.test[' + id + '] {\n color: yellow;\n}')
922 expect(style).to.contain('.test[' + id + ']:after {\n content: \'bye!\';\n}')
923 expect(style).to.contain('h1[' + id + '] {\n color: green;\n}')
924 done()
925 })
926 })
927
928 it('style import', function (done) {
929 test({
930 entry: './test/fixtures/style-import.vue'
931 }, function (window) {
932 var styles = window.document.querySelectorAll('style')
933 expect(styles[0].textContent).to.contain('h1 { color: red;\n}')
934 // import with scoped
935 var id = 'data-v-' + genId(require.resolve('./fixtures/style-import.vue'))
936 expect(styles[1].textContent).to.contain('h1[' + id + '] { color: green;\n}')
937 done()
938 })
939 })
940
941 it('template import', function (done) {
942 test({
943 entry: './test/fixtures/template-import.vue'
944 }, function (window, module) {
945 var vnode = mockRender(module)
946 // '<div><h1>hello</h1></div>'
947 expect(vnode.children[0].tag).to.equal('h1')
948 expect(vnode.children[0].children[0]).to.equal('hello')
949 done()
950 })
951 })
952
953 it('script import', function (done) {
954 test({
955 entry: './test/fixtures/script-import.vue'
956 }, function (window, module) {
957 expect(module.data().msg).to.contain('Hello from Component A!')
958 done()
959 })
960 })
961
962 it('source map', function (done) {
963 var config = Object.assign({}, globalConfig, {
964 entry: './test/fixtures/basic.vue',
965 devtool: '#source-map'
966 })
967 bundle(config, function (code) {
968 var map = mfs.readFileSync('/test.build.js.map').toString()
969 var smc = new SourceMapConsumer(JSON.parse(map))
970 var line
971 var col
972 var targetRE = /^\s+msg: 'Hello from Component A!'/
973 code.split(/\r?\n/g).some(function (l, i) {
974 if (targetRE.test(l)) {
975 line = i + 1
976 col = 0
977 return true
978 }
979 })
980 var pos = smc.originalPositionFor({
981 line: line,
982 column: col
983 })
984 expect(pos.source.indexOf('basic.vue') > -1)
985 expect(pos.line).to.equal(9)
986 done()
987 })
988 })
989
990 it('media-query', function (done) {
991 test({
992 entry: './test/fixtures/media-query.vue'
993 }, function (window) {
994 var style = window.document.querySelector('style').textContent
995 style = normalizeNewline(style)
996 var id = 'data-v-' + genId(require.resolve('./fixtures/media-query.vue'))
997 expect(style).to.contain('@media print {\n.foo[' + id + '] {\n color: #000;\n}\n}')
998 done()
999 })
1000 })
1001
1002 it.skip('extract CSS', function (done) {
1003 bundle(Object.assign({}, globalConfig, {
1004 entry: './test/fixtures/extract-css.vue',
1005 vue: {
1006 loaders: {
1007 css: ExtractTextPlugin.extract('css-loader'),
1008 stylus: ExtractTextPlugin.extract('css-loader?sourceMap!stylus-loader')
1009 }
1010 },
1011 plugins: [
1012 new ExtractTextPlugin('test.output.css')
1013 ]
1014 }), function () {
1015 var css = mfs.readFileSync('/test.output.css').toString()
1016 css = normalizeNewline(css)
1017 expect(css).to.contain('h1 {\n color: #f00;\n}\n\nh2 {\n color: green;\n}')
1018 done()
1019 })
1020 })
1021
1022 it.skip('dependency injection', function (done) {
1023 test({
1024 entry: './test/fixtures/inject.js'
1025 }, function (window) {
1026 // console.log(window.injector.toString())
1027 var module = interopDefault(window.injector({
1028 './service': {
1029 msg: 'Hello from mocked service!'
1030 }
1031 }))
1032 var vnode = mockRender(module, module.data())
1033 // <div class="msg">{{ msg }}</div>
1034 expect(vnode.tag).to.equal('div')
1035 expect(vnode.data.staticClass).to.equal('msg')
1036 expect(vnode.children[0]).to.equal('Hello from mocked service!')
1037 done()
1038 })
1039 })
1040
1041 it('translates relative URLs and respects resolve alias', function (done) {
1042 test({
1043 entry: './test/fixtures/resolve.vue',
1044 resolve: {
1045 alias: {
1046 fixtures: path.resolve(__dirname, 'fixtures')
1047 }
1048 },
1049 module: {
1050 rules: [
1051 {
1052 test: /\.vue$/,
1053 loader: loaderPath
1054 },
1055 {
1056 test: /\.png$/,
1057 loader: 'file-loader?name=[name].[hash:6].[ext]'
1058 }
1059 ]
1060 }
1061 }, function (window, module) {
1062 var vnode = mockRender(module)
1063 // <div>
1064 // <img src="logo.c9e00e.png">
1065 // <img src="logo.c9e00e.png">
1066 // </div>
1067 expect(vnode.children[0].tag).to.equal('img')
1068 expect(vnode.children[0].data.attrs.src).to.equal('logo.c9e00e.png')
1069 expect(vnode.children[2].tag).to.equal('img')
1070 expect(vnode.children[2].data.attrs.src).to.equal('logo.c9e00e.png')
1071
1072 var style = window.document.querySelector('style').textContent
1073 expect(style).to.contain('html { background-image: url(logo.c9e00e.png);\n}')
1074 expect(style).to.contain('body { background-image: url(logo.c9e00e.png);\n}')
1075 done()
1076 })
1077 })
1078
1079 it('postcss options', function (done) {
1080 test({
1081 entry: './test/fixtures/postcss.vue',
1082 vue: {
1083 postcss: {
1084 options: {
1085 parser: require('sugarss')
1086 }
1087 }
1088 }
1089 }, function (window) {
1090 var style = window.document.querySelector('style').textContent
1091 style = normalizeNewline(style)
1092 expect(style).to.contain('h1 {\n color: red;\n font-size: 14px\n}')
1093 done()
1094 })
1095 })
1096
1097 it('transpile ES2015 features in template', function (done) {
1098 test({
1099 entry: './test/fixtures/es2015.vue'
1100 }, function (window, module) {
1101 var vnode = mockRender(module, {
1102 a: 'hello',
1103 b: true
1104 })
1105 // <div :class="{[a]:true}"></div>
1106 expect(vnode.tag).to.equal('div')
1107 expect(vnode.data.class['test-hello']).to.equal(true)
1108 expect(vnode.data.class['b']).to.equal(true)
1109 done()
1110 })
1111 })
1112
1113 it('allows to export extended constructor', function (done) {
1114 test({
1115 entry: './test/fixtures/extend.vue'
1116 }, function (window, Module) {
1117 // extend.vue should export Vue constructor
1118 var vnode = mockRender(Module.options, {
1119 msg: 'success'
1120 })
1121 expect(vnode.tag).to.equal('div')
1122 expect(vnode.children[0]).to.equal('success')
1123 expect(new Module().msg === 'success')
1124 done()
1125 })
1126 })
1127
1128 it('support es compatible modules', function (done) {
1129 test({
1130 entry: './test/fixtures/basic.vue',
1131 vue: {
1132 esModule: true
1133 }
1134 }, function (window, module, rawModule) {
1135 expect(rawModule.__esModule).to.equal(true)
1136 var vnode = mockRender(rawModule.default, {
1137 msg: 'hi'
1138 })
1139 expect(vnode.tag).to.equal('h2')
1140 expect(vnode.data.staticClass).to.equal('red')
1141 expect(vnode.children[0]).to.equal('hi')
1142
1143 expect(rawModule.default.data().msg).to.contain('Hello from Component A!')
1144 done()
1145 })
1146 })
1147
1148 it('css-modules', function (done) {
1149 function testWithIdent(localIdentName, regexToMatch, cb) {
1150 test({
1151 entry: './test/fixtures/css-modules.vue',
1152 vue: {
1153 cssModules: localIdentName && {
1154 localIdentName: localIdentName
1155 }
1156 }
1157 }, function (window) {
1158 var module = window.vueModule
1159
1160 // get local class name
1161 var className = module.computed.style().red
1162 expect(className).to.match(regexToMatch)
1163
1164 // class name in style
1165 var style = [].slice.call(window.document.querySelectorAll('style')).map(function (style) {
1166 return style.textContent
1167 }).join('\n')
1168 style = normalizeNewline(style)
1169 expect(style).to.contain('.' + className + ' {\n color: red;\n}')
1170
1171 // animation name
1172 var match = style.match(/@keyframes\s+(\S+)\s+{/)
1173 expect(match).to.have.length(2)
1174 var animationName = match[1]
1175 expect(animationName).to.not.equal('fade')
1176 expect(style).to.contain('animation: ' + animationName + ' 1s;')
1177
1178 // default module + pre-processor + scoped
1179 var anotherClassName = module.computed.$style().red
1180 expect(anotherClassName).to.match(regexToMatch).and.not.equal(className)
1181 var id = 'data-v-' + genId(require.resolve('./fixtures/css-modules.vue'))
1182 expect(style).to.contain('.' + anotherClassName + '[' + id + ']')
1183
1184 cb()
1185 })
1186 }
1187 // default localIdentName
1188 testWithIdent(undefined, /^\w{23}/, function () {
1189 // specified localIdentName
1190 var ident = '[path][name]---[local]---[hash:base64:5]'
1191 var regex = /^test-fixtures-css-modules---red---\w{5}/
1192 testWithIdent(ident, regex, done)
1193 })
1194 })
1195
1196 it('css-modules in SSR', function (done) {
1197 bundle({
1198 entry: './test/fixtures/css-modules.vue',
1199 target: 'node',
1200 output: Object.assign({}, globalConfig.output, {
1201 libraryTarget: 'commonjs2'
1202 })
1203 }, function (code) {
1204 // http://stackoverflow.com/questions/17581830/load-node-js-module-from-string-in-memory
1205 function requireFromString(src, filename) {
1206 var Module = module.constructor;
1207 var m = new Module();
1208 m._compile(src, filename);
1209 return m.exports;
1210 }
1211
1212 var output = requireFromString(code, './test.build.js')
1213 expect(output.computed.style().red).to.exist
1214
1215 done()
1216 })
1217 })
1218})
1219**/