In TestCafe is there a way to know if the test passed or failed in after hook? - testing

I am trying to mark tests as pass/failed through a rest API (Zephyr) while my testcafe tests are running. I was wondering if it's possible in the after or afterEach hook to know if the test passed/failed so that I can run some script based on the result.
Something like:
test(...)
.after(async t => {
if(testFailed === true) { callApi('my test failed'); }
})

I see two ways in which to solve your task. First, do not subscribe to the after hook, but create your own reporter or modify the existing reporter. Please refer to the following article: https://devexpress.github.io/testcafe/documentation/extending-testcafe/reporter-plugin/#implementing-the-reporter
 
The most interesting method there is reportTestDone because it accepts errs as a parameter, so you can add your custom logic there.
The second approach is using sharing variables between hooks and test code
You can write your test in the following manner:
test(`test`, async t => {
await t.click('#non-existing-element');
t.ctx.passed = true;
}).after(async t => {
if (t.ctx.passed)
throw new Error('not passed');
});
Here I am using the shared passed variable between the test code and hook. If the test fails, the variable will not be set to true, and I'll get an error in the after hook.

This can be determined from the test controller, which has more information nested within it that is only visible at run time. An array containing all the errors thrown in the test is available as follows
t.testRun.errs
If the array is populated, then the test has failed.

Related

How can I create a new browser session and delete it on webdriverio?

I'm using an implementation of webdriverio with cucumberjs.
I would like that every scenario I run creates a new browser, and deletes it after the scenario finishes running.
I thought this could be achieved through the use of cucumber hooks
beforeScenario: async function (world) {
await browser.newSession(capabilities)
}
afterScenario: async function (world) {
await browser.deleteSession()
}
However, this doesn't work, using reloadSession() after the scenarios is not ideal because it reloads the browser after running individual scenarios, which is unnecessary.
I noticed that the test runner creates a new browser object every time is ran, it's there any way I can skip that and create it at the beforeScenario level?
You can handle this by creating an another class like 'DriverFactory', which takes browser name as constructor parameter. Based on this parameter, launch respective browser and return it.
In another class, create a static variable like public status driver. Assign above class returned driver object to this variable in your beforeScenario hook in case its value is undefined like:
beforeScenario: async function (world) {
if (driver === 'undefined') {
driver = DriverFactory.launchBrowser("browsername");
}
}
in this case, on every scenario this block will be executed and checks whether variable is undefined. If Yes, it creates/ launches a new browser instance, else it will not..
afterScenario: async function (world, result) {
const client = await browser.newSession(browser.capabilities);
const clientNew = Object.create(browser)
await clientNew.deleteSession()
browser.sessionId = client.sessionId
},
try this , but await browser.reloadSession() does the same thing , i am not sure what you mean by it doesn't work

How to correctly utilise redux-saga putResolve

I'm trying to sequence my API calls so that I can call an endpoint, wait for it to succeed, then select the required value out of the state.
I'm very new to redux-saga and am finding it difficult to understand how to achieve this!
What I've tried:
So we try and block whilst we perform an API call:
const resp = yield putResolve(assistantActions.fetchSustainability());
Later in the code we select the updated value out of the state:
const assistant = yield select(getAssistant);
The action that is called looks like:
export const fetchSustainability = () => ({ type: FETCH_SUSTAINABILITY });
In the saga we:
yield takeEvery(FETCH_SUSTAINABILITY, fetchSustainability);
Then the function returns a promise:
function fetchSustainability() {
return axios.get(`${url}/sustainability`);
}
I'm not sure that I've set this up any where near right as I've made lots of changes trying to get it working!
The select statement executes immediately and as the call isn't blocked the state isn't updated correctly.
Is my approach correct? If not is someone able to provide a simple working example on how to achieve a blocking call.
So the second parameter to takeEvery needs to be a generator function;
within that you can call your fetchSustainability
function* generator() {
yield call(fetchSustainability); // calls the actual function
}
// in the saga
yield takeEvery(FETCH_SUSTAINABILITY, generator);
your action fetchSustainability should return a Promise.
Here's an example to highlight the difference between put and putResolve.
https://codesandbox.io/s/redux-saga-example-x77jb
The example uses thunkMiddleware

How jasmine spy example works

All;
I am just starting learning Jasmine( version 2.0.3 ), when I got to Spies section, the first example confused me:
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456, 'another param');
});
it("tracks that the spy was called", function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("tracks all the arguments of its calls", function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456, 'another param');
});
it("stops all execution on a function", function() {
expect(bar).toBeNull();
});
});
I wonder if anyone could explain why the setBar function does not affect the bar defined inside describe block? How Jasmine spies deal with this?
Thanks
Because you are not actually executing the methods.
If you want this test to fail:
it("stops all execution on a function", function() {
expect(bar).toBeNull();
});
After these calls:
foo.setBar(123);
foo.setBar(456, 'another param');
Then you should call and.callThrough for your spy.
spyOn(foo, 'setBar').and.callThrough();
From the documentation
Spies: and.callThrough
By chaining the spy with and.callThrough, the spy will still track all
calls to it but in addition it will delegate to the actual
implementation.
With regard to your question, 'how jasmine deals with this?'
From here you can read a basic explanation:
Mocks work by implementing the proxy pattern. When you create a mock
object, it creates a proxy object that takes the place of the real
object. We can then define what methods are called and their returned
values from within our test method. Mocks can then be utilized to
retrieve run-time statistics on the spied function such as:
How many times the spied function was called.
What was the value that the function returned to the caller.
How many parameters the function was called with.
If you want all of the implementation details, you can check the Jasmine source code which is Open Source :)
In this source file CallTracker you can see how the gather data about the method calls.
A little more about the proxy pattern.

Can't perform a Laravel 4 action/route test more than once

I'm running into a Laravel 4 testing issue: An action/route test can only be run once, and it has to be the first test run. Any subsequent action/route test will fail with an exception before the assert is called.
route/action tests run as long as they are the first test run.
Non-route/action tests run normally, although they cause subsequent route/action tests to throw an exception
It's important to note that the tests in question don't fail, they throw an exception when the action is fired, for example:
Symfony\Component\Routing\Exception\RouteNotFoundException: Unable to generate a URL for the named route "home" as such route does not exist.
Sample test class:
class ExampleTest extends TestCase {
// passes
public function testOne()
{
$class = MyApp::ApiResponse();
$this->assertInstanceOf('\MyApp\Services\ApiResponse', $class);
}
// this fails unless moved the top of the file
public function testRoute()
{
$this->route('GET','home');
$this->assertTrue($this->client->getResponse()->isOk());
}
// passes
public function testTwo()
{
$class = MyApp::ProjectService();
$this->assertInstanceOf('\MyApp\Services\ProjectService', $class);
}
}
This is implementation-specific, a fresh Laravel 4 project does not exhibit the issue. What could be causing this behaviour? How would you go about tracking down the problem?
In this case, the routes file was being called using an include_once call. When subsequent tests were run the routes were empty.
Changing to include() fixed the issue exhibited in the question

How to access a function defined in a previous YUI.use() call

[I'm a YUI newbie]
I'm writing a Chrome extension that needs to change the contents of a web page created using the YUI3 framework.
I've identified that the extension, which injects javascript that runs in the page after it is loaded, must call a function that was previously defined in a YUI.add() call.
The original YUI code that runs is something like this:
YUI.add("uuu", function (c) {
...
c.theObject = niceStuff;
}
...
YUI().use("uuu", function (c) {
c.theObject.doSomething();
}
Is it possible that after this code runs, I can access a function of c.theObject?
(I understand this might go against YUI3's nice sandbox mechanism, but it's what I need to get the job done here).
You might have problems because any time a YUI() instance is created, it builds you a new sandbox. With a few exceptions, YUI modules are completely boxed by their sandbox context. For example:
YUI().use('node', function(Y1) {
YUI().use('node', function(Y2) {
assert(Y1.Node === Y2.Node) // fails!
});
});
It's very possible that you may not be able to access the specific instance of theObject that you need, if it's never assigned to a variable outside the sandbox function scope. If any instance of theObject will do, you can just call into the YUI API and get your own version to play with.
This works for me: http://jsfiddle.net/sMAQx/1/
One way to do it is to capture the YUI() instance after you 'use' it. Like this:
YUI().add("uuu", function (c) {
c.theObject = 'foo';
})
var yInstance = YUI().use("uuu", function (c) {
c.theObject = 'booyaa';
})
yInstance.use('uuu',function(c){
console.log(c.theObject)
})
// booyaa