Run function after beforeEach - mocha.js

I need to run a function before my tests, but after all beforeEaches. Is there a way of prioritise beforeEaches, reorder them or monkeypatching something so that I can run a function before test gets executed?
Reason: I want to count how many database calls my tests do, but not include those that beforeEach calls.

Mocha executes the beforeEach hooks that pertain to a test in the order in which it encountered them in your code, so there should not be a need to monkeypatch. For instance:
describe("top", () => {
beforeEach(() => {
console.log("A");
});
describe("down", () => {
beforeEach(() => {
console.log("B");
});
beforeEach(() => {
console.log("C");
// Put your code here.
});
it("test 1", () => {});
it("test 2", () => {});
});
});
The above outputs:
top
down
A
B
C
✓ test 1
A
B
C
✓ test 2

Related

Turn off clearing aliases in Cypress test

We have a number of variables from the API which are used throughout the tests. The values are saved to aliases at various points.
How can we turn off clearing aliases between test?
If we use one big test this works fine but Cypress by default clears aliases between tests, so as we break down the tests into smaller more manageable units we are breaking the code.
Simple example:
before(() => {
cy.wrap(123).as('alias')
})
it('test1', () => {
// alias is usable here
cy.get('#alias').should('eq', 123)
cy.wrap(456).as('alias2')
});
it('test2', () => {
// alias is missing here
cy.get('#alias').should('eq', 123)
cy.get('#alias2').should('eq', 456)
});
There's no configuration to turn off alias cleardown.
You would have to create a custom command to do it.
Cypress.Commands.add('keepAliases', function(aliasList) {
if (!aliasList) {
aliasList = Object.keys(this)
.filter(key => !['test', '_runnable', 'currentTest']
.includes(key))
}
aliasList.forEach(key => {
cy.wrap(this[key]).as(key)
})
})
Usage for a single test
before(() => {
cy.wrap(123).as('alias')
})
it('test1', () => {
cy.get('#alias').should('eq', 123)
cy.wrap(456).as('alias2')
});
// ✅ test passes
it('test2', () => {
cy.keepAliases()
cy.get('#alias').should('eq', 123)
cy.get('#alias2').should('eq', 456)
});
Usage for all tests
before(() => {
cy.wrap(123).as('alias')
})
beforeEach(() => {
cy.keepAliases()
})
it('test1', () => {
cy.get('#alias').should('eq', 123)
cy.wrap(456).as('alias2')
});
// ✅ test passes
it('test2', () => {
cy.get('#alias').should('eq', 123)
cy.get('#alias2').should('eq', 456)
});
According to cypress doc
aliases and properties are automatically cleaned up after each test
so with current cypress versions your goal is not achievable.
As a workaround you could use cypress.env as a storage for your tests:
Cypress.env(varName, varValue)
and using a test0 to reset all variables before each texts execution:
it('test0', () => {
// clean up all stored aliases
cy.env("var1",null);
cy.env("var2",null);
//...
});

How to test if a function asserts in a NEAR smart contract (AssemblyScript)?

I have a function in my NEAR smart-contract (AssemblyScript) that I want to test. I want to test if the assertion actually happened.
AssemblyScript
foo(id: string): boolean {
assert(id != 'bar', 'foo cannot be bar');
return true;
}
Unit test (as-pect)
describe('Contract', () => {
it('should assert', () => {
contract.foo('bar'); // <-- How to test assertion here
})
});
After running the above test, the console logs says
Failed:
should assert - foo cannot be bar
I know I can return false or throw instead of doing an assert for the above example, and I may do that instead if it makes testing easier.
use toThrow()
Like this:
describe('Contract', () => {
it('should assert', () => {
contract.foo('bar').toThrow('foo cannot be bar');
})
});
you can also use not.toThrow() to test not trowing:
it('should assert', () => {
contract.foo('foo').not.toThrow();
})
});

Cypress: Why finicky in handling spec's after hook?

Blocked by a Cypress custom command not executing properly within a spec's after hook when a test failed. Experimented with the following minimal spec examples.
Context
Testing two Cypress custom commands:
cy.cmdLogin(): Standard username password authentication
cy.cmdLogout(): cy.get('logout_button').click()
Spec #1, cy.cmdLogout() in after hook does work
Very simple Cypress tests spec, test cy.cmdLogin() with after hook with cy.cmdLogout(), works perfectly:
context('SPEC Login', () => {
after('AFTER Logout', () => {
if (this.successLogin) {
cy.cmdLogout().then(() => {
cy.log('Logout Success');
});
}
});
it('TEST Login', () => {
cy.cmdLogin().then(() => {
cy.log('Login Success');
this.successLogin = true;
});
});
});
Spec #2, cy.cmdLogout() in after hook does not work
Modified Cypress tests spec, test cy.cmdLogin() with after hook with cy.cmdLogout(), now added a test that forced failure expect(false).to.be.a('boolean').to.be.true;. The after hook cy.cmdLogout() is called and fails:
Verified that Cypress could handle cy.get('logout_button') without failure.
Yet, extending with .click(), cy.get('logout_button').click(), Cypress would throw an error: Can not perform click() on undefined.
context('SPEC Login', () => {
after('AFTER Logout', () => {
if (this.successLogin) {
cy.cmdLogout().then(() => {
cy.log('Logout Success');
});
}
});
it('TEST Login', () => {
cy.cmdLogin().then(() => {
cy.log('Login Success');
this.successLogin = true;
});
});
it('TEST Fail', () => {
expect(false).to.be.a('boolean').to.be.true;
});
});
Spec #3, removed after hook, cy.cmdLogout() moved to another test does work
Modified Cypress tests spec again and removed after hook, test cy.cmdLogin(), test forced failure, and now test cy.cmdLogout(). This works perfectly:
context('SPEC Login', () => {
it('TEST Login', () => {
cy.cmdLogin().then(() => {
cy.log('Login Success');
this.successLogin = true;
});
});
it('TEST Fail', () => {
expect(false).to.be.a('boolean').to.be.true;
});
it('TEST Logout', () => {
if (this.successLogin) {
cy.cmdLogout().then(()=> {
cy.task('log', 'Logout Success');
});
}
});
});
Insight as to why Cypress is finicky with spec's after hook would be very much appreciated
The short answer (for the general situation) is change after() hook to before() hook, but in your case that wouldn't work because this.successLogin will always be undefined inside a before.
You would need to create a cy.isLoggedIn() command or call cy.cmdLogout() unconditionally.
To get after() the logic working on a fail, use
after('AFTER Logout', () => {
cy.cmdLogout()
});
Cypress.on('fail', (error, runnable) => {
cy.cmdLogout()
throw error
})
which is equivalent to this in plain javascript
try {
some-code-that-might-error()
cy.cmdLogout() // does not run if error occurs
} catch (error) {
cy.cmdLogout() // do the logout in error situation
}

How to instruct cypress to do some actions if the testcase is passed?

I try to use aftereach() but it will execute either the testcase is passed or failed. I need to know the context of that should i use for example if condition or what?
For example:
describe('TestSuite', function(){
it('THIS TEST CASE PASSED', function(){
})
it('THIS TEST CASE FAILED', function(){
})
})
I need to make it like this. If the a testcase is passed do the actions
...
...
...
and if the testcase failed do the actions
...
...
...
You didn't give much info about your code, so I will suggest a solution that might not be suited for you. I would use a variable that gets set to "fail" if an assertion fails in the previous test and use that to determine the action in the 2nd test, e.g.
describe('check if first test passed or failed then do A or B', () => {
let result
it('test 1', () => {
cy.request({url: Cypress.env('url')}).its('status').then((status) => {
if (status === 500) {
result = 'fail'
}
})
})
it('test 2', () => {
if (result === 'fail') {
cy.log('Previous test failed, so I did Action A')
Code Action A
}
else
{
cy.log('Previous test passed, so I did Action B')
Code Action B
}
})
})

All function calls made ahead of time

I wrote a function in one of my tests. I call this function in several parts of my test. All three function calls are made at the beginning of the test, one after another, regardless of when I called them in my test.
The code looks something like this:
const doSomething = () => {
console.log('Do something')
// ...
}
describe('Foo', () => {
it('Bar', () => {
// Some tests...
doSomething()
// Some tests...
doSomething()
// Some tests...
doSomething()
})
})
In my output, I see the logs of the doSomething() three times, one after the other, before any of the test parts run.
How can I avoid these function calls being evaluated ahead of time?
Cypress performs all the actions asynchronously.
So if you want to do some action synchronously, you can wrap you code inside a then callback:
const doSomething = () => {
cy.wrap(null).then(() => {
console.log('Do something')
// ...
})
}
Please also note that any cypress command may be issued directly in the test run time:
const doSomething = () => {
cy.log('Do something')
// ...
}
Cypress will only enqueue the log command and execute it asynchronously in the cypress event loop.
Already mentioned, the .then() callback schedules your code, but chain it off the test code that it should follow.
describe('Foo', () => {
it('Bar', () => {
// Some tests...
cy.get(...)
.should(...)
.then(() => doSomething())
// Some tests...
cy.get(...)
.should(...)
.then(() => doSomething())
})
})

Resources