Can passed nightwatch.js tests be hidden in output? - nightwatch.js

The default Nightwatch.js output consumes one line per passed test. For example,
✔ Testing if element <body> contains text 'lecture is so boring' (12ms)
✔ Testing if element <button[id=btn1]> is visible (6ms)
✔ Testing if element <button[id=btn]> is visible (10ms)
✔ Testing if element <#fill1> is visible (19ms)
✔ Testing if element <#fill2> is visible (18ms)
✔ Testing if element <#fill3> is visible (20ms)
Currently Nightwatch consumes far more of my screen than the rest of my build output combined. On the CLI on Linux, appending
|grep -v "✔"
to the command mostly alleviates that but has the disadvantage of stripping colored text (even with --color=always) when calling nightwatch from gulp. Is there a configuration option or command line parameter to minimize output and only show failed tests?
Ideally, if all tests pass, I would prefer just one line of output, but that may be asking too much. Using the grep above, this still results, which remains too much for my taste.
[Nightwatch] Test Suite
=======================
ℹ Connected to localhost on port 4444 (1133ms).
Using: firefox (91.0.1) on linux 4.19.0-18-amd64 platform.
Running: Demo of Quiz
OK. 51 assertions passed. (3.498s)
I'd really just like it to say
Nightwatch: 51 assertions passed. (3.498s)
or similar.
My config file:
// Autogenerated by Nightwatch
// Refer to the online docs for more details: https://nightwatchjs.org/gettingstarted/configuration/
const Services = {}; loadServices();
module.exports = {
// An array of folders (excluding subfolders) where your tests are located;
// if this is not specified, the test source must be passed as the second argument to the test runner.
src_folders: ['src/ts/test/functional'],
// See https://nightwatchjs.org/guide/working-with-page-objects/
page_objects_path: '',
// See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
custom_commands_path: '',
// See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions
custom_assertions_path: '',
// See https://nightwatchjs.org/guide/#external-globals
globals_path : '',
webdriver: {},
test_settings: {
default: {
disable_error_log: false,
launch_url: 'https://nightwatchjs.org',
screenshots: {
enabled: false,
path: 'screens',
on_failure: true
},
desiredCapabilities: {
browserName : 'firefox'
},
webdriver: {
start_process: true,
server_path: (Services.geckodriver ? Services.geckodriver.path : '')
}
},
firefox: {
desiredCapabilities : {
browserName : 'firefox',
alwaysMatch: {
// Enable this if you encounter unexpected SSL certificate errors in Firefox
// acceptInsecureCerts: true,
'moz:firefoxOptions': {
args: [
// '-headless',
// '-verbose'
],
}
}
},
webdriver: {
start_process: true,
port: 4444,
server_path: (Services.geckodriver ? Services.geckodriver.path : ''),
cli_args: [
// very verbose geckodriver logs
// '-vv'
]
}
},
chrome: {
desiredCapabilities : {
browserName : 'chrome',
chromeOptions : {
// This tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78)
// w3c: false,
// More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/
args: [
//'--no-sandbox',
//'--ignore-certificate-errors',
//'--allow-insecure-localhost',
//'--headless'
]
}
},
webdriver: {
start_process: true,
port: 9515,
server_path: (Services.chromedriver ? Services.chromedriver.path : ''),
cli_args: [
// --verbose
]
}
},
//////////////////////////////////////////////////////////////////////////////////
// Configuration for when using the browserstack.com cloud service |
// |
// Please set the username and access key by setting the environment variables: |
// - BROWSERSTACK_USER |
// - BROWSERSTACK_KEY |
// .env files are supported |
//////////////////////////////////////////////////////////////////////////////////
browserstack: {
selenium: {
host: 'hub-cloud.browserstack.com',
port: 443
},
// More info on configuring capabilities can be found on:
// https://www.browserstack.com/automate/capabilities?tag=selenium-4
desiredCapabilities: {
'bstack:options' : {
local: 'false',
userName: '${BROWSERSTACK_USER}',
accessKey: '${BROWSERSTACK_KEY}',
}
},
disable_error_log: true,
webdriver: {
keep_alive: true,
start_process: false
}
},
'browserstack.chrome': {
extends: 'browserstack',
desiredCapabilities: {
browserName: 'chrome',
chromeOptions : {
// This tells Chromedriver to run using the legacy JSONWire protocol
// More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/
w3c: false
}
}
},
'browserstack.firefox': {
extends: 'browserstack',
desiredCapabilities: {
browserName: 'firefox'
}
},
'browserstack.ie': {
extends: 'browserstack',
desiredCapabilities: {
browserName: 'IE',
browserVersion: '11.0',
'bstack:options' : {
os: 'Windows',
osVersion: '10',
local: 'false',
seleniumVersion: '3.5.2',
resolution: '1366x768'
}
}
},
//////////////////////////////////////////////////////////////////////////////////
// Configuration for when using the Selenium service, either locally or remote, |
// like Selenium Grid |
//////////////////////////////////////////////////////////////////////////////////
selenium: {
// Selenium Server is running locally and is managed by Nightwatch
selenium: {
start_process: true,
port: 4444,
server_path: (Services.seleniumServer ? Services.seleniumServer.path : ''),
cli_args: {
'webdriver.gecko.driver': (Services.geckodriver ? Services.geckodriver.path : ''),
'webdriver.chrome.driver': (Services.chromedriver ? Services.chromedriver.path : '')
}
}
},
'selenium.chrome': {
extends: 'selenium',
desiredCapabilities: {
browserName: 'chrome',
chromeOptions : {
w3c: false
}
}
},
'selenium.firefox': {
extends: 'selenium',
desiredCapabilities: {
browserName: 'firefox',
'moz:firefoxOptions': {
args: [
// '-headless',
// '-verbose'
]
}
}
}
}
};
function loadServices() {
try {
Services.seleniumServer = require('selenium-server');
} catch (err) {}
try {
Services.chromedriver = require('chromedriver');
} catch (err) {}
try {
Services.geckodriver = require('geckodriver');
} catch (err) {}
}

Edit: Just to mark it as answered
You need to add detailed_output: false in your nightwatch config file.

Related

getByRole in Nightwatch Testing Library throws error in basic example

I keep getting an error when running a basic sample with Nightwatch.js + Testing Library:
[Ecosia Search With TL] Test Suite
==================================
ℹ Connected to localhost on port 9515 (1077ms).
Using: chrome (87.0.4280.66) on Mac OS X platform.
Running: Demo test ecosia.org
matcher.test is not a function
FAILED: 1 errors (935ms)
_________________________________________________
TEST FAILURE: 1 error during execution; 0 tests failed, 0 passed (2.779s)
✖ ecosiaSearchWithTL
– Demo test ecosia.org (935ms)
Error: [object Object]
at processTicksAndRejections (internal/process/task_queues.js:97:5)
npm ERR! Test failed. See above for more details.
This is my only test:
const { getQueriesFrom } = require('#testing-library/nightwatch')
module.exports = {
async beforeEach(browser) {
await browser.url('https://www.ecosia.org/')
},
async 'Demo test ecosia.org'(browser) {
const { getByRole } = getQueriesFrom(browser)
const searchBox = await getByRole('searchbox', { name: /search form/i })
browser.setValue(searchBox, 'nightwatch')
const submit = await getByRole('button', { name: /submit/i })
browser.click(submit)
browser.end()
}
}
My nightwatch.conf.js:
module.exports = {
src_folders: ['tests'],
webdriver: {
start_process: true,
port: 9515,
server_path: "node_modules/.bin/chromedriver",
},
test_settings: {
default: {
desiredCapabilities : {
browserName: "chrome"
}
}
}
};
Any idea why I keep getting that error?
It works flawlessly without Testing Library.

Nativescript-Angular code sharing: How do I create platform specific modules?

Imagine I have OrderComponent and CustomerComponent that represent two screens.
In the web version you can create a new customer while in the order screen by launching the customer component inside a popup. So OrderComponent references CustomerComponent directly in the template. So I have to keep both in the same FeaturesModule for this to work.
On the other hand in the Nativescript mobile version, there is no such capability and so the two components/screens are completely independent, so I would like to put them in 2 separate modules: OrderModule, and CustomerModule. And lazy load them so the app launches faster.
In my real application of course it's not just 2 components but several dozens so the mobile app performance is a more pressing issue.
When I try to add a module file with the tns extension like this: order.module.tns.ts, without the corresponding web file, it seems as if the NativeScript bundler is not picking it up, I get the following error:
ERROR: C:\...\src\app\features\orders\orders.module.ts is missing from the TypeScript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property.
at AngularCompilerPlugin.getCompiledFile (C:\Users\...\node_modules\#ngtools\webpack\src\angular_compiler_plugin.js:753:23)
at plugin.done.then (C:\Users\...\node_modules\#ngtools\webpack\src\loader.js:41:31)
at process._tickCallback (internal/process/next_tick.js:68:7)
# ../$$_lazy_route_resource lazy namespace object ./features/measurement-units/measurement-units.module
# ../node_modules/#angular/core/fesm5/core.js
# ../node_modules/nativescript-angular/platform.js
# ./main.ns.ts
But according to the docs, all I have to do to make a nativescript specific component is add it with the tns extension. Is there another step to make this work for module files?? Help is appreciated
Update
Here is my tsconfig.tns.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"~/*": [
"src/*"
],
"*": [
"./node_modules/tns-core-modules/*",
"./node_modules/*"
]
}
}
}
Update 2
My webpack.config.js:
const { join, relative, resolve, sep } = require("path");
const webpack = require("webpack");
const nsWebpack = require("nativescript-dev-webpack");
const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns-replace-bootstrap");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const { AngularCompilerPlugin } = require("#ngtools/webpack");
module.exports = env => {
// Add your custom Activities, Services and other Android app components here.
const appComponents = [
"tns-core-modules/ui/frame",
"tns-core-modules/ui/frame/activity",
];
const platform = env && (env.android && "android" || env.ios && "ios");
if (!platform) {
throw new Error("You need to provide a target platform!");
}
const projectRoot = __dirname;
// Default destination inside platforms/<platform>/...
const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";
const {
// The 'appPath' and 'appResourcesPath' values are fetched from
// the nsconfig.json configuration file
// when bundling with `tns run android|ios --bundle`.
appPath = "app",
appResourcesPath = "app/App_Resources",
// You can provide the following flags when running 'tns run android|ios'
aot, // --env.aot
snapshot, // --env.snapshot
uglify, // --env.uglify
report, // --env.report
sourceMap, // --env.sourceMap
hmr, // --env.hmr,
} = env;
const externals = (env.externals || []).map((e) => { // --env.externals
return new RegExp(e + ".*");
});
const appFullPath = resolve(projectRoot, appPath);
const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
const entryModule = `${nsWebpack.getEntryModule(appFullPath)}.ts`;
const entryPath = `.${sep}${entryModule}`;
const ngCompilerPlugin = new AngularCompilerPlugin({
hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]),
platformTransformers: aot ? [nsReplaceBootstrap(() => ngCompilerPlugin)] : null,
mainPath: resolve(appPath, entryModule),
tsConfigPath: join(__dirname, "tsconfig.tns.json"),
skipCodeGeneration: !aot,
sourceMap: !!sourceMap,
});
const config = {
mode: uglify ? "production" : "development",
context: appFullPath,
externals,
watchOptions: {
ignored: [
appResourcesFullPath,
// Don't watch hidden files
"**/.*",
]
},
target: nativescriptTarget,
entry: {
bundle: entryPath,
},
output: {
pathinfo: false,
path: dist,
libraryTarget: "commonjs2",
filename: "[name].js",
globalObject: "global",
},
resolve: {
extensions: [".ts", ".js", ".scss", ".css"],
// Resolve {N} system modules from tns-core-modules
modules: [
resolve(__dirname, "node_modules/tns-core-modules"),
resolve(__dirname, "node_modules"),
"node_modules/tns-core-modules",
"node_modules",
],
alias: {
'~': appFullPath
},
symlinks: true
},
resolveLoader: {
symlinks: false
},
node: {
// Disable node shims that conflict with NativeScript
"http": false,
"timers": false,
"setImmediate": false,
"fs": "empty",
"__dirname": false,
},
devtool: sourceMap ? "inline-source-map" : "none",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: "vendor",
chunks: "all",
test: (module, chunks) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName) ||
appComponents.some(comp => comp === moduleName);
},
enforce: true,
},
}
},
minimize: !!uglify,
minimizer: [
new UglifyJsPlugin({
parallel: true,
cache: true,
uglifyOptions: {
output: {
comments: false,
},
compress: {
// The Android SBG has problems parsing the output
// when these options are enabled
'collapse_vars': platform !== "android",
sequences: platform !== "android",
}
}
})
],
},
module: {
rules: [
{
test: new RegExp(entryPath),
use: [
// Require all Android app components
platform === "android" && {
loader: "nativescript-dev-webpack/android-app-components-loader",
options: { modules: appComponents }
},
{
loader: "nativescript-dev-webpack/bundle-config-loader",
options: {
angular: true,
loadCss: !snapshot, // load the application css if in debug mode
}
},
].filter(loader => !!loader)
},
{ test: /\.html$|\.xml$/, use: "raw-loader" },
// tns-core-modules reads the app.css and its imports using css-loader
{
test: /[\/|\\]app\.css$/,
use: {
loader: "css-loader",
options: { minimize: false, url: false },
}
},
{
test: /[\/|\\]app\.scss$/,
use: [
{ loader: "css-loader", options: { minimize: false, url: false } },
"sass-loader"
]
},
// Angular components reference css files and their imports using raw-loader
{ test: /\.css$/, exclude: /[\/|\\]app\.css$/, use: "raw-loader" },
{ test: /\.scss$/, exclude: /[\/|\\]app\.scss$/, use: ["raw-loader", "resolve-url-loader", "sass-loader"] },
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [
"nativescript-dev-webpack/moduleid-compat-loader",
"#ngtools/webpack",
]
},
// Mark files inside `#angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
{
test: /[\/\\]#angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
},
],
},
plugins: [
// Define useful constants like TNS_WEBPACK
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
"process": undefined,
}),
// Remove all files from the out dir.
new CleanWebpackPlugin([`${dist}/**/*`]),
// Copy native app resources to out dir.
new CopyWebpackPlugin([
{
from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
context: projectRoot
},
]),
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "fonts/**" },
{ from: "**/*.jpg" },
{ from: "**/*.png" },
], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
// Generate a bundle starter script and activate it in package.json
new nsWebpack.GenerateBundleStarterPlugin([
"./vendor",
"./bundle",
]),
// For instructions on how to set up workers with webpack
// check out https://github.com/nativescript/worker-loader
new NativeScriptWorkerPlugin(),
ngCompilerPlugin,
// Does IPC communication with the {N} CLI to notify events when running in watch mode.
new nsWebpack.WatchStateLoggerPlugin(),
],
};
if (report) {
// Generate report files for bundles content
config.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
generateStatsFile: true,
reportFilename: resolve(projectRoot, "report", `report.html`),
statsFilename: resolve(projectRoot, "report", `stats.json`),
}));
}
if (snapshot) {
config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
chunk: "vendor",
angular: true,
requireModules: [
"reflect-metadata",
"#angular/platform-browser",
"#angular/core",
"#angular/common",
"#angular/router",
"nativescript-angular/platform-static",
"nativescript-angular/router",
],
projectRoot,
webpackConfig: config,
}));
}
if (hmr) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
}
return config;
};

How to get nightwatch test_workers work with browserstack-local

I am trying to get Nightwatch's inbuilt parallel test_workers working with browserstack-local for local url testing.
When running tests without browserstack local, Nightwatch test_workers seem to work just fine. The same is true for running local tests without test_workers enabled.
I have tried the examples found here https://github.com/browserstack/nightwatch-browserstack but none of these uses browserstack-local in combination with Nightwatch test_workers.
When running locally with test_workers I get the following output.
Connecting local
Connected. Now testing...
Process terminated with code 0.
Has anyone else encountered similar issues?
EDIT: I have since resolved this issue and have posted an answer below
I have dumped the relevant configuration files below.
My local.conf.js
nightwatch_config = {
globals_path: 'globals.js',
output_folder: false,
src_folders: ['tests'],
selenium: {
'start_process': false,
'host': 'hub-cloud.browserstack.com',
'port': 80
},
test_workers: {
"enabled": true,
"workers":2
},
test_settings: {
default: {
desiredCapabilities: {
'browserstack.user': process.env.BROWSERSTACK_USER,
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY,
'browserstack.local': true,
'browserstack.debug': false,
}
}
}
};
// Code to copy seleniumhost/port into test settings
for (let i in nightwatch_config.test_settings) {
if (nightwatch_config.test_settings.hasOwnProperty(i)) {
let config = nightwatch_config.test_settings[i];
config['selenium_host'] = nightwatch_config.selenium.host;
config['selenium_port'] = nightwatch_config.selenium.port;
}
}
module.exports = nightwatch_config;
local.runner.js
#!/usr/bin/env node
var Nightwatch = require('nightwatch');
var browserstack = require('browserstack-local');
var bs_local;
process.env.BROWSERSTACK_ID = new Date().getTime();
try {
process.mainModule.filename = "./node_modules/.bin/nightwatch";
// Code to start browserstack local before start of test
console.log("Connecting local");
Nightwatch.bs_local = bs_local = new browserstack.Local();
bs_local.start({ 'key': process.env.BROWSERSTACK_ACCESS_KEY }, function (error) {
if (error) throw error;
console.log('Connected. Now testing...');
Nightwatch.cli(function (argv) {
Nightwatch.CliRunner(argv)
.setup(null, function () {
// Code to stop browserstack local after end of parallel test
bs_local.stop(function () { });
})
.runTests(function () {
// Code to stop browserstack local after end of single test
bs_local.stop(function () { });
});
});
});
} catch (ex) {
console.log('There was an error while starting the test runner:\n\n');
process.stderr.write(ex.stack + '\n');
process.exit(2);
}
and my package.json script
node ./local.runner.js -c ./local.conf.js
The issue here was due to the module filename being incorrectly defined in the local.runner.js
process.mainModule.filename = "./node_modules/.bin/nightwatch";
should be pointed directly at the Nightwatch file in its directory.
process.mainModule.filename = "./node_modules/nightwatch/bin/nightwatch";
The difference in these files and the exact reason for this solution working are beyond me.
The answer was derived from the "suite" runner in https://github.com/browserstack/nightwatch-browserstack
It seems you are not specifying browsers. Modify your configuration file to be inline with the following configuration file:
var browserstack = require('browserstack-local');
nightwatch_config = {
src_folders : [ "local" ],
selenium : {
"start_process" : false,
"host" : "hub-cloud.browserstack.com",
"port" : 80
},
test_workers: {
"enabled": true,
"workers":2
},
common_capabilities: {
'browserstack.user': process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME',
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY',
'browserstack.debug': true,
'browserstack.local': true
},
test_settings: {
default: {},
chrome: {
desiredCapabilities: {
browser: "chrome"
}
},
firefox: {
desiredCapabilities: {
browser: "firefox"
}
},
safari: {
desiredCapabilities: {
browser: "safari"
}
}
}
};
// Code to support common capabilites
for(var i in nightwatch_config.test_settings){
var config = nightwatch_config.test_settings[i];
config['selenium_host'] = nightwatch_config.selenium.host;
config['selenium_port'] = nightwatch_config.selenium.port;
config['desiredCapabilities'] = config['desiredCapabilities'] || {};
for(var j in nightwatch_config.common_capabilities){
config['desiredCapabilities'][j] = config['desiredCapabilities'][j] || nightwatch_config.common_capabilities[j];
}
}
module.exports = nightwatch_config;

how to debug the meanjs, node-inspector not opening debug?port=5858

I cloned the meanjs and running with npm install and grunt
at the start up it shows debugger listening on port 5858,
but when i open the chrome with
localhost:8080/debug?port=5858
it shows the webpage is not available.
is there anything i need to do to make the node-inspector debugger to work for meanjs ?
Ok, if you're using the Gruntfile from the Yeoman Generator (meanjs.org) as I presume, just run grunt debug instead of simply grunt in your console. Then the node inspector will be available at http://localhost:1337/debug?port=5858 if you have default settings like:
watch: {
serverViews: {
files: watchFiles.serverViews,
options: {
livereload: true
}
},
serverJS: {
files: watchFiles.serverJS,
tasks: ['jshint'],
options: {
livereload: true
}
},
clientViews: {
files: watchFiles.clientViews,
options: {
livereload: true,
}
},
clientJS: {
files: watchFiles.clientJS,
tasks: ['jshint'],
options: {
livereload: true
}
},
clientCSS: {
files: watchFiles.clientCSS,
tasks: ['csslint'],
options: {
livereload: true
}
}
},
nodemon: {
dev: {
script: 'server.js',
options: {
nodeArgs: ['--debug'],
ext: 'js,html',
watch: watchFiles.serverViews.concat(watchFiles.serverJS)
}
}
},
'node-inspector': {
custom: {
options: {
'web-port': 1337,
'web-host': 'localhost',
'debug-port': 5858,
'save-live-edit': true,
'no-preload': true,
'stack-trace-limit': 50,
'hidden': []
}
}
},
concurrent: {
default: ['nodemon', 'watch'],
debug: ['nodemon', 'watch', 'node-inspector'],
options: {
logConcurrentOutput: true,
limit: 10
}
}
And the main cli tasks are defined at the bottom of the gruntfile:
// Default task(s).
grunt.registerTask('default', ['lint', 'concurrent:default']);
// Debug task.
grunt.registerTask('debug', ['lint', 'concurrent:debug']);
You need to start the node inspector server, that one will listen on 8080:
node-inspector
Then you're ready to hit the debug URL

How to test Durandal.js viewmodel containing i18next implementation?

I'm new to both Durandal.js and Javascript testing with Jasmine, and need some help. I have managed to get a testing environment up and running with Karma and Jasmine, but I struggle to figure out how to test my viewmodels that contains i18next dependencies.
Here's a stripped down example of my setup:
main.js
requirejs.config({
paths: {
'models': 'models',
'text': '../lib/require/text',
'durandal': '../lib/durandal/js',
'plugins': '../lib/durandal/js/plugins',
'transitions': '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-2.3.0',
'bootstrap': '../lib/bootstrap/js/bootstrap.min',
'jquery': '../lib/jquery/jquery-1.9.1',
'i18next': '../lib/i18next/i18next.amd.withJQuery-1.7.1.min'
}
});
define(['plugins/router', 'durandal/system', 'durandal/app', 'durandal/binder', 'durandal/viewLocator', 'knockout', 'jquery', 'i18next'], function (router, system, app, binder, viewLocator, ko, $, i18n) {
app.configurePlugins({
router: true
});
app.start().then(function () {
// Setup of i18n
i18n.init({
detectFromHeaders: false,
fallbackLng: 'en',
preload: ['nb', 'en'],
supportedLngs: ['nb', 'en'],
resGetPath: 'locales/__lng__.json',
useCookie: true,
}, function () {
binder.binding = function (obj, view) {
$(view).i18n();
};
viewLocator.useConvention();
app.setRoot('viewmodels/shell');
});
});
});
shell.js
define(['plugins/router', 'durandal/app', 'i18next'], function (router, app, i18n) {
return {
router: router,
activate: function () {
return router.map([
{ route: '', title: i18n.t('pageTitle'), moduleId: 'viewmodels/ViewModel', nav: true }
]).buildNavigationModel().mapUnknownRoutes('viewmodels/ViewModel', 'unknown').activate({
pushState: false,
hashChange: true
});
}
};
});
test.js (own require.js config)
var tests = [];
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
if (/.*\.spec\.js$/.test(file)) {
tests.push(file);
}
}
}
//Workaround for the timestamp issue
for (var file in window.__karma__.files) {
window.__karma__.files[file.replace(/^\//, '')] = window.__karma__.files[file];
}
require.config({
baseUrl: 'base',
paths: {
'models': 'app/models',
'viewModels': 'app/viewmodels',
'specs': 'tests/specs/',
'text': 'lib/require/text',
'durandal': 'lib/durandal/js',
'plugins': 'lib/durandal/js/plugins',
'transitions': 'lib/durandal/js/transitions',
'knockout': 'lib/knockout/knockout-2.3.0',
'jquery': 'lib/jquery/jquery-1.9.1',
'i18next': 'lib/i18next/i18next.amd.withJQuery-1.7.1.min',
},
// ask Require.js to load these files (all our tests)
deps: tests,
// start test run, once Require.js is done
callback: window.__karma__.start
});
karma.conf.js
// Karma configuration
module.exports = function (config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// frameworks to use
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
{ pattern: 'lib/jquery/jquery-1.9.1.js', watched: false, included: true, served: true },
{ pattern: 'tests/jasmine/jasmine-jquery.js', watched: false, served: true, included: true },
{ pattern: 'tests/specs/**/*.js', included: false },
{ pattern: 'tests/sinon.js', included: false },
{ pattern: 'lib/**/*.js', included: false, served: true },
{ pattern: 'app/**/*.js', included: false, served: true },
'tests/test.js',
//Serve the fixtures
{ pattern: 'app/**/*.html', watched: true, served: true, included: false },
{ pattern: 'app/**/*.json', watched: true, served: true, included: false },
{ pattern: 'tests/**/*.json', watched: true, served: true, included: false }
],
preprocessors: [
{ '**/*.html': '' }
],
// list of files to exclude
exclude: [
'foundation/*.js',
'require.js',
'init.js',
'jasmine/jasmine.js',
'jasmine/jasmine-html.js',
'node_modules/**/*.html'
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
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: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
//browsers: ['Chrome', 'Firefox', 'IE'],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
ViewModel (i18next):
define(["i18next"], function (i18n) {
var pageTitle = i18n.t("pageTitle");
return {
pageTitle: pageTitle
};
});
Spec (i18next)
define(['viewModels/ViewModel'], function (ViewModel) {
describe("Viewmodel test", function () {
it("should be testable", function () {
expect(true).toEqual(true);
});
it("should have title", function () {
expect(ViewModel.pageTitle).not.toBeEmpty();
});
});
});
Test runner output
PhantomJS 1.9.2 (Mac OS X) ERROR
ReferenceError: Can't find variable: initialized
at /Users/xxx/dev/projectXYZ/lib/i18next/i18next.amd.withJQuery-1.7.1.min.js:5
PhantomJS 1.9.2 (Mac OS X): Executed 0 of 0 ERROR (0.312 secs / 0 secs)
ViewModel (wo/i18next):
define([], function () {
var pageTitle = "This is the page title";
return {
pageTitle: pageTitle
};
});
Spec (wo/i18next)
define(['viewModels/ViewModel'], function (ViewModel) {
describe("Viewmodel test", function () {
it("should be testable", function () {
expect(true).toEqual(true);
});
it("should have title", function () {
expect(ViewModel.pageTitle).toEqual("This is the page title");
});
});
});
Test runner output (wo/i18next)
PhantomJS 1.9.2 (Mac OS X): Executed 2 of 2 SUCCESS (0.312 secs / 0.164 secs)
I guess I have to somehow initialize i18next, but I dont know how.
Any help would be much appreciated.
Regards,
Remi
UPDATE
This is what I ended up doing:
test.js:
'i18next-original': 'lib/i18next/i18next.amd.withJQuery-1.7.1.min',
'i18next': 'tests/i18n-test'
i18n-test.js:
define(['i18next-original'], function (i18noriginal) {
'use strict';
i18noriginal.init({
lng: 'nb',
detectFromHeaders: false,
fallbackLng: 'en',
preload: ['nb', 'en'],
supportedLngs: ['nb', 'en'],
resGetPath: 'base/locales/__lng__.json',
useCookie: false,
debug: false,
getAsync: false
});
return i18noriginal;
});
karma.conf.js:
{ pattern: 'tests/i18n-test.js', included: false, served: true },
Hallais Remi!
You can initialize i18next in beforeEach like this:
define(['viewModels/ViewModel', 'i18next'], function (ViewModel, i18n) {
describe("Viewmodel test", function () {
beforeEach(function() {
var initialized = false;
runs(function() {
i18n.init({
detectFromHeaders: false,
fallbackLng: 'en',
preload: ['nb', 'en'],
supportedLngs: ['nb', 'en'],
resGetPath: 'locales/__lng__.json',
useCookie: true
}, function () { initialized = true; });
});
waitsFor(function() {
return initialized;
}, 'i18n to initialize', 100);
});
it("should be testable", function () {
expect(true).toEqual(true);
});
it("should have title", function () {
expect(ViewModel.pageTitle).not.toBeEmpty();
});
});
});
For focusing the test on code inside the viewModel itself you can consider instead to mock the i18n object used in your viewModel.
testr.js might help you mock require.js dependencies: https://github.com/medallia/testr.js

Resources