Hur man konfigurerar Typescript, Karma, Webpack för att köra tester i webbläsaren
Jag utvecklar ett spel med Phaser3 och bestämde mig för att jag skulle vilja lägga till några tester för vissa komponenter i mitt spel.
Jag använder Typescript 3.3 och webpack 4 som mina huvudverktyg. Jag skulle vilja köra tester i webbläsaren där vissa tester kan bero på Phaser-spelbiblioteket. Tidigare har jag använt Karma+Jasmine för att testa Angular.js-appar, så jag tänkte att jag skulle köra på det.
Efter lite installation fick jag testerna att köra, men av någon anledning kan testfilerna inte importera andra moduler utan ger istället fel
Compiled with warnings.
ℹ 「wdm」: Compiling...
✖ 「wdm」:
ERROR in ./src/test/core/EntityFactory.spec.ts
Module not found: Error: Can't resolve './foo' in '<path to the project>/src/test/core'
@ ./src/test/core/EntityFactory.spec.ts 1:0-26
ℹ 「wdm」: Failed to compile.
Module not found: Error: Can't resolve './foo' in '/<path to the project>/src/test/core'
Den nämnda /test/core-katalogen innehåller filerna EntityFactory.spec.ts och foo.ts. Importen är skriven i sviten som:
import thing from './foo';
Nedan är min karma-konfigurationsfil och den webpack-konfiguration den använder:
// Karma configuration
// Generated on Sun Mar 17 2019 17:03:14 GMT+0200 (EET)
const webpackConfig = require('./webpack.config').test;
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'**/*.spec.ts'
// each file acts as entry point for the webpack configuration
],
mime: {
"text/x-typescript": ["ts", "tsx"],
},
// list of files / patterns to exclude
exclude: [
// '**/*.spec.ts'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
// add webpack as preprocessor
'**/*.spec.ts': [ 'webpack' ],
},
webpack: webpackConfig,
webpackMiddleware: {
// webpack-dev-middleware configuration
// i. e.
stats: 'errors-only'
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
})
}
Och Webpack-konfiguration:
const baseConfig = {
entry: './src/index.ts',
mode: 'development',
output: {
path: path.resolve(__dirname, 'build'),
publicPath: '/',
chunkFilename: '[name].js',
filename: '[name].js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
// Source maps support ('inline-source-map' also works)
devtool: 'source-map',
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader'
},
{
test: /\.js$/,
use: ['source-map-loader'],
enforce: 'pre'
}
]
},
optimization: {
runtimeChunk: {
name: 'manifest'
},
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'initial'
}
}
}
},
plugins: [
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, 'assets'),
to: path.resolve(__dirname, 'build', 'assets')
}
]),
new webpack.DefinePlugin({
CANVAS_RENDERER: JSON.stringify(true),
WEBGL_RENDERER: JSON.stringify(true)
}),
new MiniHtmlWebpackPlugin({
context: {
title: 'Phaser game'
},
// FIXME: CSS-loader and default minithmlwebpack template would probably handle this better
template: ({js, title, publicPath } ) =>
`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${title}</title>
<style type = "text/css">
body {
padding: 0;
margin: 0;
}
canvas {
display:block;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
${generateJSReferences(js, publicPath)}
</body>
</html>
`
})
]
};
function getTestConfig() {
const config = _.cloneDeep(baseConfig);
delete config.entry;
return config;
}
Funktionen getTestConfig() ändrar baseConfig lite grann och skickar resultatet till Karma-konfigurationen.
Slutligen utvecklingsberoenden om det finns något där som kan hjälpa:
"devDependencies": {
"@types/jasmine": "^3.3.10",
"browser-sync": "^2.26.3",
"browser-sync-webpack-plugin": "^2.2.2",
"copy-webpack-plugin": "^4.6.0",
"jasmine": "^3.3.1",
"karma": "^4.0.1",
"karma-chrome-launcher": "^2.2.0",
"karma-jasmine": "^2.0.1",
"karma-webpack": "^3.0.5",
"mini-html-webpack-plugin": "^0.2.3",
"prettier": "^1.16.4",
"source-map-loader": "^0.2.4",
"ts-loader": "^5.3.3",
"tslint": "^5.12.1",
"tslint-config-prettier": "^1.18.0",
"typescript": "^3.3",
"webpack": "^4.29.3",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.14"
},
Så min fråga är, varför verkar testerna inte kunna importera de moduler jag vill testa? Är problemet i Webpack, Karma eller Typescript?
Svar #1
Detta låter som att Typescript inte kompilerar modulen du försöker inkludera (foo). Det skulle vara bra att sätta ihop ett litet testfall som reproducerar felet, men du bör kontrollera din tsconfig.json för att säkerställa att den inkluderar all kod som du vill kunna testa.
Jag har en separat tsconfig.test.json som täcker huvudingångspunkten för applikationen (files: ["src/index.ts"]) och även alla tester (include: ["src/**/*.spec.ts"]). Om du går den vägen kan du kanske skapa en tsconfig.base.json med gemensamma alternativ, och sedan inkludera den i din produktions-tsconfig.json samt i test-tsconfig.json. Du behöver sedan peka din Webpack-konfiguration på rätt fil, som
{
test: /\.tsx?$/,
use: {
loader: 'ts-loader',
options: {
configFile: 'tsconfig.test.json',
}
}
},
Du kan ställa in configFile till tsconfig.json som standard, sedan kan din getTestConfig()-funktion ändra den för att användas av karma-webpack.
