UNPKG

@vue/vue3-jest

Version:

Jest Vue transform

197 lines (167 loc) 5.82 kB
const { parse, compileTemplate, compileScript } = require('@vue/compiler-sfc') const { transform } = require('@babel/core') const babelTransformer = require('babel-jest').default const typescriptTransformer = require('./transformers/typescript') const coffeescriptTransformer = require('./transformers/coffee') const _processStyle = require('./process-style') const processCustomBlocks = require('./process-custom-blocks') const getTypeScriptConfig = require('./utils').getTypeScriptConfig const getVueJestConfig = require('./utils').getVueJestConfig const logResultErrors = require('./utils').logResultErrors const stripInlineSourceMap = require('./utils').stripInlineSourceMap const getCustomTransformer = require('./utils').getCustomTransformer const loadSrc = require('./utils').loadSrc const generateCode = require('./generate-code') const mapLines = require('./map-lines') const vueComponentNamespace = require('./constants').vueComponentNamespace function resolveTransformer(lang = 'js', vueJestConfig) { const transformer = getCustomTransformer(vueJestConfig['transform'], lang) if (/^typescript$|tsx?$/.test(lang)) { return transformer || typescriptTransformer(lang) } else if (/^coffee$|coffeescript$/.test(lang)) { return transformer || coffeescriptTransformer } else { return transformer || babelTransformer.createTransformer() } } function processScript(scriptPart, filePath, config) { if (!scriptPart) { return null } let content = scriptPart.content let filename = filePath if (scriptPart.src) { content = loadSrc(scriptPart.src, filePath) filename = scriptPart.src } const vueJestConfig = getVueJestConfig(config) const transformer = resolveTransformer(scriptPart.lang, vueJestConfig) const result = transformer.process(content, filename, config) result.code = stripInlineSourceMap(result.code) result.map = mapLines(scriptPart.map, result.map) return result } function processScriptSetup(descriptor, filePath, config) { if (!descriptor.scriptSetup) { return null } const vueJestConfig = getVueJestConfig(config) const content = compileScript(descriptor, { id: filePath, refTransform: true, ...vueJestConfig.compilerOptions }) const contentMap = mapLines(descriptor.scriptSetup.map, content.map) const transformer = resolveTransformer( descriptor.scriptSetup.lang, vueJestConfig ) const result = transformer.process(content.content, filePath, config) result.map = mapLines(contentMap, result.map) return result } /** * Process SFC <template> section. * @param {import('@vue/compiler-sfc').SFCDescriptor} descriptor * @param {string} filename * @param {import('@jest/transform').TransformOptions} config */ function processTemplate(descriptor, filename, config) { const { template, scriptSetup } = descriptor if (!template) { return null } const vueJestConfig = getVueJestConfig(config) if (template.src) { template.content = loadSrc(template.src, filename) } let bindings if (scriptSetup) { const scriptSetupResult = compileScript(descriptor, { id: filename, refTransform: true, ...vueJestConfig.compilerOptions }) bindings = scriptSetupResult.bindings } // Since Vue 3.2.13, it's possible to use TypeScript in templates, // but this needs the `isTS` option of the compiler. // We could let users set it themselves, but vue-loader and vite automatically add it // if the script is in TypeScript, so let's do the same for a seamless experience. const lang = (descriptor.scriptSetup && descriptor.scriptSetup.lang) || (descriptor.script && descriptor.script.lang) const isTS = /^typescript$|tsx?$/.test(lang) const result = compileTemplate({ id: filename, source: template.content, filename, preprocessLang: template.lang, preprocessOptions: vueJestConfig[template.lang], compilerOptions: { bindingMetadata: bindings, mode: 'module', isTS, ...vueJestConfig.compilerOptions } }) logResultErrors(result) // TypeScript if (isTS) { const tsconfig = getTypeScriptConfig(vueJestConfig.tsConfig) if (tsconfig) { const { transpileModule } = require('typescript') const { outputText } = transpileModule(result.code, { tsconfig }) return { code: outputText } } } // babel const babelify = transform(result.code, { filename: 'file.js', presets: ['@babel/preset-env'] }) return { code: babelify.code } } function processStyle(styles, filename, config) { if (!styles) { return null } const filteredStyles = styles .filter(style => style.module) .map(style => ({ code: _processStyle(style, filename, config), moduleName: style.module === true ? '$style' : style.module })) return filteredStyles.length ? filteredStyles : null } module.exports = function(src, filename, config) { const { descriptor } = parse(src, { filename }) const componentNamespace = getVueJestConfig(config)['componentNamespace'] || vueComponentNamespace const templateResult = processTemplate(descriptor, filename, config) const stylesResult = processStyle(descriptor.styles, filename, config) const customBlocksResult = processCustomBlocks( descriptor.customBlocks, filename, componentNamespace, config ) let scriptResult const scriptSetupResult = processScriptSetup(descriptor, filename, config) if (!scriptSetupResult) { scriptResult = processScript(descriptor.script, filename, config) } const output = generateCode({ scriptResult, scriptSetupResult, templateResult, customBlocksResult, componentNamespace, filename, stylesResult }) return { code: output.code, map: output.map.toString() } }