-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow before() hook to be called before describe() also instead of only it() OR beforeDescribe() hook #1628
Comments
I'm having the exact same problem. My example is: var expect = require('chai').expect;
var credentials = null;
// File
describe(require('path').basename(__filename), function() {
before(function(done) {
return myRequestLib.getCredentials(function(err, crd) {
if (err)
return done(err);
credentials = crd;
return done();
});
});
describe('do', function() {
// Route: /v1/:credential/doSomething
var routeDoSomething = '/v1/' + credentials.userId + '/doSomething';
describe(routeDoSomething, function() {
// Test #1: List
describe('GET', function() {
it('should return a 200', function(done) {
return myRequestLib.get(myRequestLib.baseUri, routeDoSomething, {
'Authorization': credentials.userName,
})
.expect(200)
.end(function(err, res) {
if (err) return done(new Error((err.message || err) + ' (body was: ' + JSON.stringify(res ? res.body : null) + ')'));
expect(res.body).to.exist;
return done();
});
});
});
});
});
}); Output:
It could easily be fixed by postponing the Regards, P.S.: I somehow feel I'm out offtopic, so, if I am, please ignore my comment. |
var getRouteDoSomething = function() {
return '/v1/' + credentials.userId + '/doSomething';
} Or you could even make the credentials an argument. Is it enough of a fix for you? |
For his example, it can be a fix.
|
I just don't see how you could need it when you can set variables inside the describe('setting vars inside before', function () {
before(function () {
this.credentials = {id: 123};
})
it('it should work', function () {
(this.credentials.id).should.equal(123);
})
}) |
The problem still holds. mayurvirkar, I don't know what your use case it -- and don't hesitate to tell me if you feel I pollute the conversation -- but having It might be needed for logging, caching or anything you'd want to do but exclude from @dasilvacontin, about what you suggested, it does not help with the fact that I can't use the route string in the first |
@Pampattitude but why do you need to do it in the You can do the assignments and the logs inside the hooks. If you don't feel like you can explain your case-scenario via words, feel free to show code. |
I'm pretty certain you're both looking for the var foo;
// process.nextTick to be replaced with your async setup function
process.nextTick(function() {
foo = 'bar'; // or "credentials" object w/ user id
run(); // this is exposed when running mocha with the --delay flag
});
describe(require('path').basename(__filename), function() {
describe(foo, function() {
it('should be true', function() {
require('assert')(true);
});
})
}); |
@dasilvacontin @Pampattitude is saying you can't define a |
(Basically, what happens is there's an implicit This works here because |
Hey @boneskull, and plus I also dont think adding a beforeDescribe() hook will be really that difficult :) |
|
+1 I need it for dynamic tests with loops like so first, I tried this: describe('@Test_Enrichment*', function () {
var self = null; // ok, great, we can work with self ....
before(function () {
this.config = require('univ-config')(this.test.parent.title, 'setup/testSetup');
this.constants = this.config.get('sc_constants');
this.serverURL = this.config.get('test_env').smartconnect_server_config.url;
this.serverPort = this.config.get('test_env').smartconnect_server_config.port;
self.testCases = [];
// Payloads
var files = fs.readdirSync(__dirname + '/test_data/enriched_payloads');
for (var i in files) {
if (path.extname(files[i]) === '.json') {
self.testCases.push(__dirname + '/test_data/enriched_payloads/' + files[i]);
}
}
});
describe('start', function () {
before(function(done){
done(); // nothing here...yet...
});
self.testCases.forEach(function (json, index) { // self is null !!!
describe('test enrichment', function () {
it('[test] ' + path.basename(json), function (done) {
var jsonDataForEnrichment = require(json);
jsonDataForEnrichment.customer.accountnum = "8497404620452729";
jsonDataForEnrichment.customer.data.accountnum = "8497404620452729";
var options = {
url: self.serverURL + ':' + self.serverPort + '/event',
json: true,
body: jsonDataForEnrichment,
method: 'POST'
};
request(options, function (error, response, body) {
if (error) {
cb(error);
}
else {
assert(response.statusCode == 201, "Error: Response Code");
cb(null);
}
});
});
});
});
});
}); then I just kicked the can further down the road by trying this: describe('@Test_Enrichment*', function () {
var self = null; // ok, great, we can work with self ....
before(function () {
this.config = require('univ-config')(this.test.parent.title, 'setup/testSetup');
this.constants = this.config.get('sc_constants');
this.serverURL = this.config.get('test_env').smartconnect_server_config.url;
this.serverPort = this.config.get('test_env').smartconnect_server_config.port;
});
describe('start', function () {
before(function(){
self.testCases = [];
// Payloads
var files = fs.readdirSync(__dirname + '/test_data/enriched_payloads');
for (var i in files) {
if (path.extname(files[i]) === '.json') {
self.testCases.push(__dirname + '/test_data/enriched_payloads/' + files[i]);
}
}
});
self.testCases.forEach(function (json, index) { //self is null !!!
describe('test enrichment', function () {
it('[test] ' + path.basename(json), function (done) {
var jsonDataForEnrichment = require(json);
jsonDataForEnrichment.customer.accountnum = "8497404620452729";
jsonDataForEnrichment.customer.data.accountnum = "8497404620452729";
var options = {
url: self.serverURL + ':' + self.serverPort + '/event',
json: true,
body: jsonDataForEnrichment,
method: 'POST'
};
request(options, function (error, response, body) {
if (error) {
cb(error);
}
else {
assert(response.statusCode == 201, "Error: Response Code");
cb(null);
}
});
});
});
});
});
}); I am totally HOSED because I cannot nest it()s, but I can't use self.testCases, because the before hook doesn't run before the describe, only before the it() so it turns out, unless you can help me, I do NEED a before hook for describe |
Unless I'm mistaken, you don't need to put it in the hook. You don't have to rely on hooks for test setup, especially when generating specs. See http://mochajs.org/#dynamically-generating-tests describe('@Test_Enrichment*', function () {
var config, constants, serverURL, serverPort;
before(function () {
// This doesn't even need to be in the hook
config = require('univ-config')(this.test.parent.title, 'setup/testSetup');
constants = config.get('sc_constants');
serverURL = config.get('test_env').smartconnect_server_config.url;
serverPort = config.get('test_env').smartconnect_server_config.port;
});
describe('start', function () {
var dir = __dirname + '/test_data/enriched_payloads';
var files = fs.readdirSync(dir).filter(function(file) {
return (path.extname(file) === '.json');
}).map(function(file) {
return __dirname + '/test_data/enriched_payloads/' + file;
});
files.forEach(function(file) {
it('[test] ' + path.basename(file), function (done) {
var jsonDataForEnrichment = require(file);
jsonDataForEnrichment.customer.accountnum = "8497404620452729";
jsonDataForEnrichment.customer.data.accountnum = "8497404620452729";
var options = {
url: serverURL + ':' + serverPort + '/event',
json: true,
body: jsonDataForEnrichment,
method: 'POST'
};
request(options, function (error, response, body) {
if (error) return done(error);
assert(response.statusCode == 201, "Error: Response Code");
done();
});
});
});
});
}); |
thanks @danielstjules , that worked very well, but re: the line "// This doesn't even need to be in the (before) hook" - as it stands, it does need to be in the hook because of the following line which contains "this.test.parent.title" which leads me to another beef with Mocha, why the context isn't that consistent between before() it() and describe() |
I'm not sure why you can't hardcode the string? You're defining the title as |
thanks, I looked into it, FYI in the describe call back, you can use 'this.title' instead of this.test.parent.title in the before hook. this keeps it dynamic and you can share code between tests |
so I removed the before hook as you suggested |
I need this feature, because within before I execute some async code by preparing date for test. |
@OhDavit, is the async code needed in order to define the tests, or only in order to run them? If it's only needed to run them, you should be able to use a |
we have some nested tests that all have common setup, but we'd like that common setup to run before each |
@bridiver Sounds like you're looking for plain old Basically, |
No, that is definitely not what I'm looking for. I want a common setup to run once for each describe block. 'before' only runs once for the entire block and all nested blocks, not once for each nested block
… On May 16, 2017, at 8:19 PM, Scott Santucci ***@***.***> wrote:
@bridiver Sounds like you're looking for plain old before hooks? You can put one in each describe block and it will run only once before all of that block's it tests. You can also put it in an outer describe block and it will only run once even if there are inner describe blocks, if you want to share the resources that were set up (or you can even put it outside any describe block if you want it to be shared across all the tests). And if you do need it to run multiple times but it should run the same thing each time, since JavaScript functions are first-class you can just write the function elsewhere and pass it into multiple different before calls.
Basically, --delay is for defining the suite asynchronously and before is for everything else.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I need to learn to stop giving people all the possible angles... Here's the money quote:
In other words, instead of this: describe("outer", function() {
someNewHookMochaMustImplement(function () {
console.log("I run at the start of each nested describe!")
})
describe("inner 1", function() {
// multiple `it` here
})
describe("inner 2", function() {
// multiple `it` here
})
}) You can just do this: function reusableSetup() {
console.log("I should be used at the start of each describe!")
}
describe("outer", function() {
describe("inner 1", function() {
before(reusableSetup)
// multiple `it` here
})
describe("inner 2", function() {
before(reusableSetup)
// multiple `it` here
})
}) Now, I'm not necessarily saying there are no disadvantages to the latter over the former or no advantages to the former over the latter. But I am saying, this can be done without a new hook, so if you want to argue for it you'll need to make a more specific case that the difference between those two ways of doing it, one of which is already available, outweighs the added maintenance cost and increased user learning curve of adding Yet Another Hook Variation. (Keep in mind there are... a lot of different possible behaviors for hooks, so much so that we have multiple issues open already about whether the hooks we already have behave as they ought.) Also, this is a somewhat old issue and wasn't actually about your suggestion as far as I can tell -- there doesn't seem to be any prior discussion of hooks that automatically run before multiple |
For future reference for anyone else digging up this issue, so that the last thing on the page is the answer: Is the async code needed in order to define the tests, i.e. to determine the number of tests or their names? Or only in order to run them?
|
Something from a new mocha user. Learning mocha was really fast, but this is the only case which wasn't intuitive for me. I really expected to find data in my next describe block from the before hook of the parent describe block.
Code from testResponseObjStructure
|
describe('Requesting response from "validateResponse" function using invalid data', () => {
let response;
const someInvalidData = null;
before(async () => { // <= maybe wait for answer?
const wrapped = test.wrap(myFunctions.validateResponse);
response = await wrapped(someInvalidData);
});
describe('Checking if response is valid', () => {
testResponseObjStructure(response); // @this place response is still null
});
}); |
Maybe for easier testing this code reproduces the same error: AssertionError: expected null to be an object //index.test.js
const testResponseObjStructure = require('./test.response');
describe.only('Testing validateResponse function', () => {
describe('Requesting response from validateResponse function using invalid data', () => {
let response = null;
before(async () => {
response = await {}; // here i get the response from server
});
describe('Checking if response is valid', () => {
testResponseObjStructure(response); //@this place response is still null
});
});
}); //test.response.js
const expect = require('chai').expect;
module.exports = function(response) {
it('Expect response to be an Object', () => {
expect(response).to.be.an('Object');
});
}; |
const asyncAnswer = null;
before(doHereAsyncStuff and get asyncAnswer);
describe('foo', function() {
it(`bar`, function(done1) {
done1();
describe('baz', function() {
it(`Start real test with asyncAnswer`, function(done) {
Here real test with asyncAnswer
});
});
});
}); |
@SpiritOfSpirt As far as I know, you can't define new suites and tests after test execution has started. But I may be wrong. @Delilovic I'd suggest writing all your code/logic inside hooks and tests. In other words, things that get run during test execution. ( |
I want get some async data in before() hook , but it only gets executed before it(),
|
describe('waiting', function() {
it(`async data`, function(done1) {
done1();
describe(asyncData.name, () => {
asyncData.children.forEach(elder => {
describe(elder.name, () => {
elder.children.forEach(child => {
it(child.name, () => {
console.log(child.name)
})
})
})
})
})
})
})
// try this
пт, 21 трав. 2021 о 10:39 bx2651 ***@***.***> пише:
… I want get some async data in before() hook , but it only gets executed
before it(),
how should i do ?
describe("my test", () => {
let asyncData
before(() => {
asyncData = getAsyncData()
// asyncData = {
// name: grandfather,
// children: [
// {
// name: father,
// children: [
// { name: Lily },
// { name: Lucy }]
// },
// {
// name: uncle,
// children: []
// }]
// }
})
describe(asyncData.name, () => {
asyncData.children.forEach(elder => {
describe(elder.name, () => {
elder.children.forEach(child => {
it(child.name, () => {
console.log(child.name)
})
})
})
})
})
})
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1628 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACTYYZLO6O5YJXPS7JWMGMDTOYE4RANCNFSM4A6UDGWA>
.
|
Hello,
First of all, Mocha is a GREAT testing framework. It has amost everything except one feature which i would like it to have.
If we define a code in before() hook, it only gets executed before it(),
So called before() hook before describe() or added a beforeDescribe() hook.
Is it possible to add?
The text was updated successfully, but these errors were encountered: