Hello,
I try to use chai and the expect syntax in strict mode, and I have an error "TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"
Before to make a change, and because I don't want to make a change on it, what is the purpose of this argument ? Nobody use expect and strict mode ? Thanks
Hey @wadouk thanks for the issue.
Could you please show how you're using "use strict"; in your code? It sounds like you may be leaking strict mode into other scripts. I personally use "use strict"; all the time with Chai, and I've never had an issue.
Thank you @keithamus for your quick answer not like mine.
It's quite strange, i have made a quick test and it's worked as expected https://github.com/wadouk/hello-chai
I try to understand in my other codebase and I will come back later to give other feedback.
Let me know @wadouk when you have a reduced test case that shows the same error that you're seeing locally :smile:
I haven't done all what I think but I will explain a little more my context, in case that tell you something.
It fail when I load some js with karma that use mocha as framework, babel to transpile to es5 and jsx too. Something in the stack seems to leak the strict mode.
Do you smell any strange thing ? Any advice ?
Well, babel always adds "use strict"; to the top of any compiled output. If you're simply concatenating your output files without wrapping them, then this can certainly leak into outer scopes.
If you were to write <script type="text/javascript>"use strict";</script> on any webpage, you've switched on "use strict"; for every script on that page (citation).
Similarly, if you're concatenating files without wrapping them - it'll be the same effect. Suppose I had two files;
// file1
"use strict";
function Foo(){}
// file2
// not strict
function Bar() { return arguments.callee; }
If I were to concat these files together, I'd end up with the following:
// file1
"use strict";
function Foo(){}
// file2
function Bar() { return arguments.callee; }
Hopefully you can see that "use strict"; has leaked into Bar()'s code, because it is in the outer-most scope.
The way to prevent this is putting "use strict"; into a function scope to prevent it leaking out. You could do this a few ways. Given our two files from above, one way would be to simply wrap each one in an IIFE. Then when they are concatenated, they'll still keep their function scopes:
// file1
(function () {
"use strict";
function Foo(){}
}());
// file2
(function () {
// not strict
function Bar() { return arguments.callee; }
}());
Another way would be to use a tool to automatically do this for you. Browserify will do this for you - it wraps every module in its own function scope. Browserify also has a Babel transform which lets you tie the two together in one step - simplifying your translation phase.
I hope this helps you @wadouk. If you have any more troubles, feel free to comment on this issue, or open a new one.
Thank you for your explanation. I have missed that all was bundle with webpack. @clementdubois have upgraded the previous project that shows the problem (in history). He found that excluding the node_modules of webpack solve the problem. Thanks for your help, it's precious.
:smile:
I am also using webpack and babel for my project. I am trying to incorporate karma, mocha, and chai right now. I have gotten the same error about 'use strict' and I'm afraid that I do not understand @keithamus's proposed solution.
I am not familiar with the # no-strict notation that you are using. I tried some googling but to no avail. I have put some simple code into a directory (just node_modules, package.json, and the following two files) and it is still producing the error that was cited above. Would you mind taking a look at what I might try @keithamus?
here is my spec.js file
(function() {
var assert = require('assert');
describe("split", () => {
it("should work as normal", () => {
assert.equal('the kittens are in the bath'.split(' ')[1],'kittens');
});
});
var expect = require('chai').expect;
describe("a duck", () => {
it("should weigh the same as a witch", () => {
expect('a duck').to.be.a(typeof('a witch'));
expect('a duck').to.have.length('a witch'.length);
});
});
})();
here is my karma.config.js file
var webpack = require('webpack');
module.exports = function(config) {
config.set({
// ... normal karma configuration
basePath: '',
frameworks: ['mocha'],
browsers: ['Chrome'],
files: [
// all files ending in "_test"
'*[Ss]pec.js',
],
preprocessors: {
// add webpack as preprocessor
'*[Ss]pec.js': ['webpack']
},
webpack: {
resolve: {
extensions: ["", ".js"]
},
module: {
loaders: [
{ test: /\.js$/, loader: "babel" }
]
}
},
webpackMiddleware: {
// webpack-dev-middleware configuration
// i. e.
noInfo: true
},
plugins: [
require("karma-mocha"),
require("karma-chrome-launcher"),
require("karma-spec-reporter"),
require("karma-webpack")
]
});
};
Sorry @GerryFudd I must have been tired that day - I've edited my comment and cleared it up - there is no such thing as a # no-strict directive - it was meant to be a comment to illustrate the "strictness" state that the code is in.
The take-away is that there are two levels of "use strict"; - globally scoped (e.g. putting "use strict;" at the top of a file) and function scoped (e.g. putting "use strict"; inside of a function declaration). Using "use strict" in a global scope will effect all of the code in that file - which becomes a problem when the files are concatenated.
You can read more about "use strict" on the MDN website here: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Strict_mode. If you're using the directive then I thoroughly recommend reading that page from head to tail.
As for your code - there is nothing I can see where you're using a global version of "use strict" and so the code you've shown doesn't exhibit the problem - the problem lies somewhere else, in another piece of code. If I were you I'd check the rest of the codebase to see where you've used "use strict";
In the example I showed the two files that I showed were the extent of the codebase. I would guess that use strict is being inserted by
loaders: [
{ test: /\.js$/, loader: "babel" }
]
in the karma.config.js file. babel inserts 'use strict' in the es5 that it generates.
babel does indeed insert "use strict";. You might want to take a look at something like karma-browserify which may solve your problem. However I have limited time to help you here I'm afraid, but good luck!
I am using a very simple starter repo https://github.com/turingschool-examples/game-time-starter-kit that is using webpack, mocha, and chai. A direct clone of the app, npm install, npm start, and a visit to localhost:8080/test.html will show that the current test is passing
const chai = require('chai');
const assert = chai.assert;
describe('my test suite', function () {
it('should work', function () {
assert(true);
});
});
However, if I change this to use expect
const chai = require('chai');
const expect = chai.expect;
describe('my test suite', function () {
it('should work', function () {
expect(true).to.be.true;
});
});
I get the error from the test
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
The webpack configuration
module: {
loaders: [
{ test: /\.js$/, exclude: '/node_modules/', loader: 'babel-loader' },
...
Any reason at all chai's assert would work but expect fails for this?
is your exclude: '/node_modules/' meant to be exclude: /node_modules/ perhaps?
@keithamus, yes :expressionless: I didn't even recognize that. Thank you very much, that fixed my problem!
I have the same error.
Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
I declare use strict; in every .js file in my app on the very first line. Also in my mocha test files that use chai':
'use strict';
const util = require('util');
const assert = require('assert');
const chaiHttp = require('chai-http');
const chai = require('chai');
const expect = chai.expect;
chai.use(chaiHttp);
What do I do wrong? How to get rid of it?
@wzup This issue is from 2015. Please open up a new issue that includes a reduced test case that demonstrates the problem you're running into. I tried running the following code with Mocha/Chai (v4 and v3.5) and it didn't throw any errors:
'use strict';
const util = require('util');
const assert = require('assert');
const chaiHttp = require('chai-http');
const chai = require('chai');
const expect = chai.expect;
chai.use(chaiHttp);
describe('testing', function () {
it('testing123', function () {
expect(1).to.equal(1);
});
});
@meeber
Installing chai properly solved the issue with Uncaught TypeError: 'caller', 'callee', and 'arguments'
$ npm i --save-dev chai
+-- [email protected]
| +-- [email protected]
| +-- [email protected]
| | `-- [email protected]
| +-- [email protected]
| +-- [email protected]
| `-- [email protected]
`-- [email protected]
`-- [email protected]
+-- [email protected]
| `-- [email protected]
`-- [email protected]
In order to try chai out with httprequests, I installed only chai-http. And not chai itself. But were using both of them:
'use strict';
const chaiHttp = require('chai-http');
const chai = require('chai');
const expect = chai.expect;
chai.use(chaiHttp);
So I've tried to installed chai explicitly and apparently it solved the issue. I can use expect and the error isn't thrown any more.
Most helpful comment
is your
exclude: '/node_modules/'meant to beexclude: /node_modules/perhaps?