Open crishushu opened 7 years ago
Do you have an example of what necessitated multiple programatic runs of mocha?
I have the same issue: We have a test framework that runs tests written in mocha after doing some device setup. We earlier had a repeat feature where we called mocha.run n times if that feature was enabled.
We haven't tested this feature from long time but realized today that it is broken and we get same error as @crishushu mentioned.
Please confirm if Mocha supports repeating tests which can be controlled as an argument? I am aware of function within it/describe.
thanks
It is really hard to judge what this could be without a code example, including a setup. Out of curiosity have you looked https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically ?
The wiki describes that the run method returns a Runnable, which might help you debug. For example: try running your second test after the first has completed and see if that helps:
Mocha.run().on('test end', runAgainFunc);
@tgirishkumar
Please confirm if Mocha supports repeating tests which can be controlled as an argument? I am aware of function within it/describe.
I am not sure what you mean here, could you elaborate?
I meant the retry feature: https://mochajs.org/#retry-tests , we are aware of it but wanted to retry/repeat tests without code changes.
thanks
Here is another example of someone raising the issue:
https://github.com/adamgruber/mochawesome/issues/79, Look at last comment:
Please note: this error happens in mochawesome but caused by this issue in Mocha inside, i tested by reproducing below issue and then remove mochawesome and then i find current issue.
Here's my code:
import * as path from 'path';
import * as fs from 'fs';
import * as Mocha from 'mocha';
import * as React from 'react';
import * as chokidar from 'chokidar';
let mocha: Mocha = new Mocha(
{
reporter: 'mochawesome',
reporterOptions:
{
reportDir: __dirname + '/../../public/mochawesome'
}
});
let testsPath: string = __dirname + '/../../tests/';
let fileList: Array<string> = fs.readdirSync(testsPath).filter(file => file.split('.').pop() == 'js');
fileList.forEach (file =>
{
console.log(file);
mocha.addFile(path.join(testsPath, file));
});
function Invalidate()
{
fileList.forEach (p =>
{
let fullPath = path.join(testsPath, p);
p = path.resolve(fullPath);
delete require.cache[require.resolve(p)];
});
}
export default class Tests extends React.Component<{}, {}>
{
componentWillMount()
{
//mocha.run();
let watcher = chokidar.watch(testsPath, {persistent: true});
watcher.on('change', path =>
{
console.log('change');
Invalidate();
mocha.run();
//this.forceUpdate();
});
watcher.on('add', p =>
{
if (p.split('.').pop() == 'js')
{
console.log('add');
Invalidate();
mocha.addFile(p);
mocha.run();
//this.forceUpdate();
}
});
}
render()
{
return (
<html>
<body>
<iframe src='/mocha/mochawesome.html' width='100%' height='100%'/>
</body>
</html>
);
}
}
And my test code:
"use strict";
const chai_1 = require("chai");
describe('testing', function () {
it('will equal 1', () => {
chai_1.expect(1).to.equal(2);
});
});
When the add or watch event is called more than once, it fails.```
Using 3.2.0 as well * edit: same behavior with 3.1.2 I am getting the same error and I am running mocha programatically already. My dept has a shared web component with multiple versions and we are testing that we did not break any version as prior versions of the component could be used by other teams. So we run the same tests on multiple versions of a component. As a side note, we use a SemVer check when new tests are added or need to be skipped.
The error seems to occur on the first line of code on the second time the file is run because I cannot get anything including logs. There are no problems or errors when I attempt to run only 1 version (so one run of the tests).
I thought maybe if I didn't use addFile multiple times that would work, but it did not make a difference.
Just a guess, I was wondering if the test is being cached like a require then would it need to be "unregistered" so it can be run again with new information?
Here is a brief output from my tests: global-nav-module_5.0.0 Component Tests Suite1 √ module should be added and render with option parameters true (12341ms)
1 passing (12s)
Second Run - I noticed that the 5.0.0 (is a var) that is not being updated to display 5.0.1 * global-nav-module_5.0.0 Component Tests global-nav-module_5.0.0 Component Tests Suite1 1) "before all" hook
0 passing (3ms) 1 failing
1) global-nav-module_5.0.0 Component Tests global-nav-module_5.0.0 Component Tests Suite1 "before all" hook: TypeError: Cannot read property 'call' of undefined
@tgirishkumar thank you for clarifying. I have never used mocha for React tests, nor have had a need for using retries on failed tests. I have generally setup tests to always run in one command (mocha <....>
) from the command line. I would imagine it's easier to setup CI scripts that way, but have no way of comparing since I have never tried to do it the other way.
It is possible mocha is relying on something in the global state or loading setup multiple times. Hard to trace without a reproducible unit test / stack trace. Maybe with @elevow and @crishushu we can create a reproducible small unit test, track down the issue, and then submit a PR for the mocha team. They mentioned on their site that they are in dire need of help maintaining the project 😄
Yesterday I was playing with different versions of mocha. AFAIK the latest release where running mocha with same suite/spec setting multiple times is supported, is 2.3.0. @dennisbaskin just out of curiosity is there any reason why the feature (yes, I consider it as one) has been disabled. I assume that it happened deliberately.
I was able to make a small version of the failure. Hopefully someone can duplicate it. one.test.js is just a it statement with console.log();
const Mocha = require('mocha');
const path = require('path');
const async = require('async');
const mocha = new Mocha({
reporter: 'spec',
});
const counter = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const cwd = process.cwd();
mocha.addFile(path.join(cwd, 'one.test.js'));
async.eachLimit(counter, 1, (iCounter, eachCallback) => {
mocha.run((failures) => {
eachCallback();
});
});
TypeError: Cannot read property 'call' of undefined
edit: I tried moving the addFile command inside and outside of the eachLimit and both give the failure
Hey after some testing the issue seems to be specific to async.eachLimit for me.
@crishushu I would not able to answer your question as to why. I am not directly involved on the contributing team, just trying to help triage issu.es since they need help.
@elevow I will try to play around with your example, thanks for setting that up.
Guys, any update on this?
I have same problem. I just tried to set up mocha programmatically and have just one test is expect(1).toBe(1)
. No fancy stuff, like react or enzyme is loaded.
I load one test file
mocha.add('my.test.js')
then i run the tests.
mocha.run();
setTimeout(()=>{ mocha.run(); }, 5000);
First time it runs fine, after 5s it throws me an error. This is the full error stack
TypeError: Cannot read property 'call' of undefined at callFn ([__dirname]\node_modules\mocha\lib\runnable.js:348:20) at Test.Runnable.run ([__dirname]\node_modules\mocha\lib\runnable.js:340:7) at Runner.runTest ([__dirname]\node_modules\mocha\lib\runner.js:443:10) at [__dirname]\node_modules\mocha\lib\runner.js:549:12 at next ([__dirname]\node_modules\mocha\lib\runner.js:361:14) at [__dirname]\node_modules\mocha\lib\runner.js:371:7 at next ([__dirname]\node_modules\mocha\lib\runner.js:295:14) at Immediate.<anonymous> ([__dirname]\node_modules\mocha\lib\runner.js:339:5) at runCallback (timers.js:800:20) at tryOnImmediate (timers.js:762:5)
I think you should have a look at grunt-loop-mocha.
I use it for my Selenium WebDriver tests.
https://github.com/grawk/grunt-loop-mocha
My understanding is that mocha is a unit testing framework and so it creates only one instance/process of your tests. So, when you try to execute the same test, it does not execute before and after statements.
Grunt-loop-mocha on other hand helps you create the new instance for each specification. So, it will even execute before and after statements with the different configuration. I guess that's what you are looking for.
+1
mocha --compilers js:babel-register --allow-uncaught --full-trace --no-warnings --recursive tests/e2e-tests
got this error
Frontend Testing "before all" hook: open browser: TypeError: Cannot read property 'call' of undefined at callFn (/usr/src/app/node_modules/mocha/lib/runnable.js:348:20) at Hook.Runnable.run (/usr/src/app/node_modules/mocha/lib/runnable.js:340:7) at next (/usr/src/app/node_modules/mocha/lib/runner.js:309:10) at Immediate.
(/usr/src/app/node_modules/mocha/lib/runner.js:339:5) at runCallback (timers.js:781:20) at tryOnImmediate (timers.js:743:5) at processImmediate [as _immediateCallback] (timers.js:714:5) Frontend Testing "after all" hook: quit browser: TypeError: Cannot read property 'call' of undefined at callFn (/usr/src/app/node_modules/mocha/lib/runnable.js:348:20) at Hook.Runnable.run (/usr/src/app/node_modules/mocha/lib/runnable.js:340:7) at next (/usr/src/app/node_modules/mocha/lib/runner.js:309:10) at Immediate.
(/usr/src/app/node_modules/mocha/lib/runner.js:339:5) at runCallback (timers.js:781:20) at tryOnImmediate (timers.js:743:5) at processImmediate [as _immediateCallback] (timers.js:714:5)
my test
import config from 'config';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import test from 'selenium-webdriver/testing';
import webdriver from 'selenium-webdriver';
import proxy from 'selenium-webdriver/proxy';
import chrome from 'selenium-webdriver/chrome';
// Helper objects for performing actions.
import { WebDriverManager, WebDriverHelper as helper } from 'wp-e2e-webdriver';
// We're going to use the ShopPage and CartPage objects for this tutorial.
import { ShopPage, CartPage } from 'wc-e2e-page-objects';
chai.use( chaiAsPromised );
const assert = chai.assert;
const chromedriver = require('chromedriver');
const chromeCapabilities = webdriver.Capabilities.chrome();
chromeCapabilities.set('chromeOptions', {args: ['--headless --no-sandbox user-agent=Mozilla/5.0 (wp-e2e-tests) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36' ]});
const pref = new webdriver.logging.Preferences();
pref.setLevel( 'browser', webdriver.logging.Level.SEVERE );
let manager;
let driver;
test.describe( 'Frontend Testing', function() {
// Set up the driver and manager before testing starts.
test.before( 'open browser', function() {
driver = new webdriver.Builder()
.forBrowser('chrome')
.usingServer( config.get("url") )
.withCapabilities(chromeCapabilities)
.setLoggingPrefs(pref)
.setProxy(proxy.direct())
.build();
driver.getSession().then( function( sessionid ) {
driver.allPassed = true;
driver.sessionID = sessionid.id_;
} );
helper.clearCookiesAndDeleteLocalStorage( driver );
} );
// Tests will go here.
test.it( 'Has shop page', () => {
// Create a new Shop page object.
const shopPage = new ShopPage( driver, { url: config.get('url').concat( '/shop' ) } );
assert.instanceOf(shopPage, ShopPage, 'shopPage instance of ShopPage');
} );
// Close the browser after finished testing.
test.after( 'quit browser', () => {
driver.sleep( config.get('startBrowserTimeoutMs') ).then( () => {
return driver.quit();
} );
} );
} );
I'm running in a docker environment with
node 8.5.0 npm 5.4.2 mocha 3.5.3
This worked for me, if anyone is still looking for a solution
const purge = function (allFiles) {
allFiles.forEach(file => {
delete require.cache[file];
});
};
// use this function when rerunning tests
const rerun = function () {
purge(allFiles);
mocha.suite = mocha.suite.clone();
mocha.suite.ctx = new Mocha.Context();
mocha.ui("bdd");
mocha.files = allFiles;
mocha.run()
};
I am seeing this issue too using Mocha 5.2.0 - here is my stacktrace:
TypeError: Cannot read property 'call' of undefined
at callFn (/.../node_modules/mocha/lib/runnable.js:372:21)
at Test.Runnable.run (/.../node_modules/mocha/lib/runnable.js:364:7)
at Runner.runTest (/.../node_modules/mocha/lib/runner.js:455:10)
at /.../node_modules/mocha/lib/runner.js:573:12
at next (/.../node_modules/mocha/lib/runner.js:369:14)
at /.../node_modules/mocha/lib/runner.js:379:7
at next (/.../node_modules/mocha/lib/runner.js:303:14)
at Immediate.<anonymous> (/...node_modules/mocha/lib/runner.js:347:5)
at runCallback (timers.js:794:20)
at tryOnImmediate (timers.js:752:5)
at processImmediate [as _immediateCallback] (timers.js:729:5)
I am writing a library where I want to compare the output to console of a reporter based with and without my library .. which is why I need to be able to re-run the same test twice, programatically.
When inspecting the Mocha.Test
objects I see that they are missing a fn
property the second time they run, which probably is why runnable.js:372
is calling an undefined function.
It looks like a Mocha.Suite
is cleaning up by deleting these fn
properties to avoid memory leaks https://github.com/mochajs/mocha/blob/master/lib/runner.js#L817-L819.
I ultimately gave up and just reinstantiated the mocha instance between runs - remembering to clear node.js require cache (delete require.cache[testPath]
) between runs.
I clean the require cache up by using the clear-require component,
and it works every time, the code as follows:
const clearRequire = require('clear-require');
clearRequire.match(new RegExp('mocha'));//must be here
clearRequire.match(new RegExp('your-test-js-file'));//must be here
more details :
const clearRequire = require('clear-require');
function testMochaClick()
{
clearRequire.match(new RegExp('mocha'));
clearRequire.match(new RegExp('commtest'));
let Mocha = require('mocha');
let mocha = new Mocha({
reporter: 'mochawesome',
reporterOptions: {
reportDir: './resources/app/report',
}
})
mocha.addFile('./resources/app/case/commtest.js');
mocha.run();
}
https://mochajs.org/api/mocha#loadFiles
The current codebase needs mocha
to be reinstantiated between runs due to internal implementation issues.
Related: #1938
Looking back at this issue and #1938: fixing it would be a pretty significant internal refactor. I think we can accept PRs for it, but note that per #5027 it'll be a while before we can review them.
taken from https://cdnjs.com/libraries/mocha