Closed papercuptech closed 6 years ago
Have you taken a look at PR #3399?
@plroebuck That PR appears to not be backwards compatible and seems to primarily address providing lambdas access to context.
mocha-ctx also enables lambdas to access context, but in a backwards compatible way (i.e. does not require changing what is passed to lambda, so passing 'done' still works). Further, this is a minor feature of mocha-ctx, but should address #2767, #2657, #2018, #1856.
mocha-ctx's larger value is being able to let lower contexts set higher context properties that are being shared, and that each test truly has its own context, which should address #2014, #2140, #2914, #2977, #797.
mocha-ctx also provides control of globals in context; i.e. things running in a given context can see globals differently, or be restricted from even accessing some, and mocha-ctx will correctly housekeep saving and restoring as hierarchical contexts are entered and left, which should address #2656.
Additionally, the behavior mocha-ctx provides is only explicitly enabled for a given context (and all things running in it), so you can have some sub-contexts that use it and some that don't, which should allow for easier adoption.
Lastly, all these features should make it much easier to compose contexts and tests, so more types of integration testing can more easily be done with mocha.
@plroebuck things like this are now a little easier.
var function testUtil() {
assert(context().testProp === true)
}
var tests = () => {
it('uses shared context', () => {
assert(context().shared === 1)
})
it('uses test context', () => {
context().testProp = true
testUtil()
})
it('uses test context, but fails', () => {
// testUtil will fail, as 'testProp' not defined;
// each test now has own context
testUtil()
})
it('uses global', () => {
assert(someGlobal === 'read only')
})
it('sets shared context', function() {
this.shared = 42
// context().shared = 42 would work too
})
it('really is "this" context', () => {
context().skip()
})
}
describe('define context tests need', () => {
before(() => {
// here is where 'magic' happens, and also activates per-test context
context({
shared: 0,
sharedFn: () => context().shared - 42
})
})
describe('provide specific context', () => {
before(() => {
context().shared = 1
context({
globals: {
someGlobal: undefined
// now anything that gets or sets 'someGlobal' will throw
}
})
})
// fails merely from attempting to access (get) global 'someGlobal'
tests()
})
// context can still be used as alias for 'describe', but not other way around
context('provide some other specific context', () => {
before(() => {
context().shared = 1000
// can get but not set 'someGlobal'
context({globals: {someGlobal: 'read only'}})
})
// fails on context().shared not being 1 (it's 1000)
tests()
it('shared', function() {
assert(this.shared === 42)
assert(this.sharedFn() === 0)
})
})
})
What is the value of mocha-ctx
over just using scope defined variables?
describe('mocha with context variables', () => {
const context = {
cool: 'stuff!',
fn: () => 'I see cool ' + context.cool
};
it('can not do this: what would the point of that even be anyway?', function() {
assert(this === context)
})
describe('layer 1', () => {
it('can do other stuff too', () => {
// this will NOT create a 'cool' property on layer 1 context
// but will actually set 'cool' property at top context (or wherever
// 'cool' was defined in context hierarchy)
context.cool = 'way'
assert(context.fn() === 'I see cool way')
this.timeout(-42)
this.skip()
})
})
})
@Munter In your example, the test 'can do other stuff too' can not be composed into other describes. Your example test is the same functionally, but is coupled and hard coded to the const context
. You can do what you've shown, but mocha-ctx offers much more compos-ability. Look at my comment and sample code just preceding your comment.
Your test can not do this: what... is missing the point. mocha-ctx lets () => {}
get tothis
via context()
without passing as an argument and thus not breaking compatibility; in fact anything can get to context()
.
Thanks for the serious effort writing this.
Sadly I feel that this feature adds extra complexity to Mocha.
mocha-ctx
is already doing this.@Bamieh
@Bamieh Consider these simplifications:
Calling context()
becomes the normative way of always getting access to current test context.
it('test', function() {this})
, but can now always use it('test', () => {context()})
or it('test', function() {context()})
Every test now gets its own completely isolated context that has nothing shared by default
Globals are usually not good, but sometimes have to be dealt with, and now each test context can get its own 'global' environment (mostly)
Provides a means to completely decouple defining context, from implementing an instance of context, to something running in a type of context. This should make fluid composition of context and tests nicer, and mocha could be used for more kinds of testing beyond just unit testing, like small to medium integration testing (not that it can't already be).
Its all backwards compatible, btw.
mocha-ctx is currently brittle, with respect to how it patches mocha; ideally it should just be part of it.
If you truly believe these things are not of the same ethos as mocha, and testing generally, please feel free to close this issue, although it would be interesting to hear from others on the matter.
Calling context()
rather then this
would be helpful. Then I can always use arrow function. Now I have to temporary disable the tslint rule only-arrow-functions
in order to access this
in test case.
@Bamieh
context()
becomes the singular way to access test context.context()
this.foo = 1
and the next test will see this.foo
; i.e. mocha currently shares context between tests by default, contrary to your statement "sharing state between contexts [and tests] is a bad practice".
context({ someProp: 'shared' })
from a before()
hook becomes the singular and only way to explicitly declare shared context, because the default becomes that nothing is shared. (Note: calling context({})
activates per-test context only within that context (and descendants), making the context-per-test semantic opt-in, explicit, and backwards compatible)context({prop: 'state'})
, must be called).
@Bamieh Would you please elaborate on why you believe mocha should not be providing this kind of control over the environment; I had previously believed controlling the environment in which things are tested within was exactly what mocha was meant to facilitate.
Out of scope
Prerequisites
faq
labelnode node_modules/.bin/mocha --version
(Local) andmocha --version
(Global). We recommend avoiding the use of globally installed Mocha.Description
When I install and use 'mocha-ctx', I get enhanced control of context! It seems like it keeps doing this every time I use it with mocha.
Steps to Reproduce
npm i mocha-ctx
Expected behavior: [What you expect to happen] That someone, somewhere will jump up and down in joy.
Actual behavior: [What actually happens] That they will smile too!, and that mocha will want these features as part of mocha.
Reproduces how often: [What percentage of the time does it reproduce?] 100%
Versions
1.0.0-a.0
Additional Information
Additional 'bugs'
More details at https://github.com/papercuptech/mocha-context