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

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

Related

How to test with Response.OnCompleted delegate in a finally block

I have the following netcore 2.2 controller method that I am trying to write an xUnit integration test for:
private readonly ISoapSvc _soapSvc;
private readonly IRepositorySvc _repositorySvc;
public SnowConnectorController(ISoapSvc soapSvc, IRepositorySvc repositorySvc)
{
_soapSvc = soapSvc;
_repositorySvc = repositorySvc;
}
[Route("accept")]
[HttpPost]
[Produces("text/xml")]
public async Task<IActionResult> Accept([FromBody] XDocument soapRequest)
{
try
{
var response = new CreateRes
{
Body = new Body
{
Response = new Response
{
Status = "Accepted"
}
}
};
return Ok(response);
}
finally
{
// After the first API call completes
Response.OnCompleted(async () =>
{
// Run the close method
await Close(soapRequest);
});
}
}
The catch block runs and does the things it needs to, then the finally block runs and does things it needs to do after the request in the catch finishes per design.
Close has been both a private method . It started as a public controller method but I don't need to expose it for function so moved it to private method status.
Here's an integration test I started with the intention of just testing the try portion of the code:
[Fact]
public async Task AlwaysReturnAcceptedResponse()
{
// Arrange------
// Build mocks so that we can inject them in our system under tests constructor
var mockSoapSvc = new Mock<ISoapSvc>();
var mockRepositorySvc = new Mock<IRepositorySvc>();
// Build system under test(sut)
var sut = new SnowConnectorController(mockSoapSvc.Object, mockRepositorySvc.Object);
var mockRequest = XDocument.Load("..\\..\\..\\mockRequest.xml");
// Act------
// Form and send test request to test system
var actualResult = await sut.Accept(mockRequest);
var actualValue = actualResult.GetType().GetProperty("Value").GetValue(actualResult);
// Assert------
// The returned object from the method call should be of type CreateRes
Assert.IsType<CreateRes>(actualValue);
}
I am super new to testing... I've been writing the test and feeling my way through the problem. I started by entering the controller method not really knowing where it would go. The test works through the try method, and then an exception is thrown once it hits the delegate in the finally block.
It looks like my test will have to run through to the results of the finally block unless there is a way to tell it to stop with the catch blocks execution?
That's fine, i'm learning, but the problem with that approach for me now is that the HttpResponse's Response.OnCompleted delegate in the finally block returns null when my test is running and I haven't been successful at figuring out what I can do to not make it null - because it is null, it throws this when my unit test is executing -
System.NullReferenceException: 'Object reference not set to an instance of an object.'
*One thought that occurred was that if I was to make the private Close method a public controller method, and then make the Accept method not have the finally block, I could create a third controller method that does the try finally action by running the two controller methods and then just test the individual controller methods that are strung together with the third. However, it doesn't feel right because I would be exposing methods just for the sake of unit testing and I don't need Close to be exposed.
If the above idea is not the right approach, I am wondering what is, and if I just need to test through end to end, how I would get over the null httpresponse?
Any ideas would be appreciated. Thank you, SO community!
EDIT - Updated Test that works after the accepted answer was implemented. Thanks!
[Fact]
public async Task AlwaysReturnAcceptedResponse()
{
// Arrange------
// Build mocks so that we can inject them in our system under tests constructor
var mockSoapSvc = new Mock<ISoapSvc>();
var mockRepositorySvc = new Mock<IRepositorySvc>();
// Build system under test(sut)
var sut = new SnowConnectorController(mockSoapSvc.Object, mockRepositorySvc.Object)
{
// Supply mocked ControllerContext and HttpContext so that finally block doesnt fail test
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext()
}
};
var mockRequest = XDocument.Load("..\\..\\..\\mockRequest.xml");
// Act------
// Form and send test request to test system
var actualResult = await sut.Accept(mockRequest);
var actualValue = actualResult.GetType().GetProperty("Value").GetValue(actualResult);
// Assert------
// The returned object from the method call should be of type CreateRes
Assert.IsType<CreateRes>(actualValue);
}
Curious what you are doing in the Close method against the input parameter.
Does it have to happen after response is being sent? It might not always happen as you would expect, see here.
Regardless though, during runtime asp.net core runtime sets a lot of properties on the controller including ControllerContext, HttpContext, Request, Response etc.
But those won't be available in unit testing since there is no asp.net core runtime there.
If you really want to test this, you'll have to mock them.
Here is the ControllerBase source code.
As we can see, ControllerBase.Response simply returns ControllerBase.HttpContext.Response, and ControllerBase.HttpContext is a getter from ControllerBase.ControllerContext. This means you'll have to mock a ControllerContext (and the nested HttpContext as well as HttpResponse) and assign it to your controller in the setup phase.
Furthermore, the OnCompleted callback won't get called in unit test either. If you want to unit test that part, you'll have to trigger it manually.
Personally I think it's too much hassle beside the open bug I mentioned above.
I would suggest you move the closing logic (if it's really necessary) to a IDisposable scoped service and handle that in the Dispose instead - assuming it's not a computation heavy operation which can impact the response latency.

RN with Firestore unable to wait for Promise to resolve

I have a simple call to Firestore to write a doc and then wait for the doc to finish writing before changing state of the parent. However, the parent state is being changed too fast, resulting in reading fields that I think have not yet been written/propagated. I tried adding a delay with setTimeout and it seems ignored. How can I make sure the state change is absolutely only called after the Firestore doc is written completely?
The code:
updateDBEntry(stateObj) {
var that = this;
var docRef = firebase.firestore().collection('sessions').doc(this.state.userID);
docRef.get().then((doc) => {
if (!doc.exists) {
const timestamp = firebase.firestore.FieldValue.serverTimestamp();
var duration = (stateObj.seshDuration) ? stateObj.seshDuration : 1;
docRef.set({
seshName: stateObj.seshName,
seshStreet: stateObj.seshStreet,
seshZipcode: stateObj.seshZipcode,
seshDuration: duration,
seshDesc: stateObj.seshDesc,
seshTime: timestamp,
}).then(() => {
var handleToUpdate = that.props.handleToUpdate;
setTimeout(() => {
handleToUpdate(1); //this changes the parent's state
}, 10000);
});
}
});
}
I'm not sure exactly the problem you're running into here, mostly because you've only shown this one function, and not how you're using it in the rest of your app. But I can tell you three things for sure:
When the promise from set() resolves successfully, you can be certain the document is written.
get() and set() are asynchronous, and so is then(). They all return promises the represent async work.
Item 2 means that your entire function updateDBEntry() is also asynchronous and returns immediately, before any of the work is complete.
Because this entire function is async, when it returns, the document will not have been created yet. Instead, maybe this function should return that resolves only after all the work is complete, so that the caller can also use it set up some code to execute after the work is done.

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

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.

Dojo 1.7 how to use dojo components outside of require()

I have created Dojo widget like below using AMD loader in Dojo 1.7.2
var myCpane;
require([
"dijit/layout/ContentPane"
], function(ContentPane) {
myCpane = new ContentPane();
});
myCpane.startup(); // It gives 'myCpane' as undefined
In the above example, in the last statment, the variable 'myCpane' is coming as 'undefined', if I use the 'myCpane.startup()' inside the 'require()' callback function then, it will work fine.
But I want to use that 'myCpane' variable on outside of the 'require' function (for many reasons). I know the 'require()' callback function execution delayed due to the component loading process by Dojo.
My question is,
How to block the 'require()' function until it completes to execute it's callback function.
So the variable 'myCpane' will not be 'undefined' when the control come out from the 'require()' function
===========================================================
To overcome this issue, I have written a small function to load the modules and wait until the module load complete
LoadModule: function(modulePath) { // modulePath = "dijit/layout/ContentPane"
var moduleObject = undefined;
require({async: false}, [modulePath], function(getModuleObject) {
moduleObject = getModuleObject;
});
// Wait until the module loads completes
while(moduleObject === undefined);
// Return the loaded module.
return moduleObject;
}
The output of the function is always executing the while loop, the control never comes inside of 'require()'s callback function to set the value to the variable "moduleObject".
When the 'require()' function will call it's callback function? I have verified using the browser debugger window the file 'ContentPane.js' is loaded properly, but the callback function is not called, If I comment the while loop then, the callback is called properly.
When the control will come inside of the callback function in my case ?
I'm not sure what are you about to achieve, but it looks for me like a programming anti-pattern. Anyway you can achieve this via dojo/_base/Deferred:
require(["dojo/_base/Deferred"], function(Deferred) {
var deferred = new Deferred();
require(["dijit/layout/ContentPane"], function(ContentPane) {
var myCpane = new ContentPane();
deferred.resolve(myCpane); //resolve, i.e. call `then` callback
});
deferred.then(function(myCpane) {
console.log(myCpane);
myCpane.startup();
});
});​
Mess with it at jsFiddle: http://jsfiddle.net/phusick/HYQEd/
I would also suggest you consider one of these two strategies to achieve the same:
Give the ContentPane an id and obtain its reference via dijit's registry.byId().
Create ContentPane instance in a separate module and expose it as a return value of that module:
// file: myCpane.js
define(["dijit/layout/ContentPane"], function(ContentPane) {
var myCpane = new ContentPane();
return myCpane;
});
// file: main.js
require(["./myCpane"], function(myCpane) {
myCpane.startup();
});
I think this goes more to scope issue then amd loader question; consider
var x;
function foo() {
x = { bar : 1 };
}
// you wouldn't expect to have reference to x variable here
if(typeof x.bar == "undefined") console.log(x);
// foo() is called at a random time - or in dojo loader case, when modules are present
foo();
console.log(x.bar); // oohh now its there ^^
x in this case translates to your myCpane, which is declared as variable (var $$) inside a function, the function that is callback for when loader is done requireing modules.
The Deferred is a nice handler for this as stated below. A slight overhead though, if youre allready in a detached (async) function flow. For full control, look into require() you could do this as well:
var myCpane;
require({ async: false }, [
"dijit/layout/ContentPane"
], function(ContentPane) {
myCpane = new ContentPane();
});
// require does not return until module loading is done and callback executed
myCpane.startup();

Have multiple calls wait on the same internal async task

(Note: this is an over-simplified scenario to demonstrate my coding issue.)
I have the following class interface:
public class CustomerService
{
Task<IEnumerable<Customer>> FindCustomersInArea(String areaName);
Task<Customer> GetCustomerByName(String name);
:
}
This is the client-side of a RESTful API which loads a list of Customer objects from the server then exposes methods that allows client code to consume and work against that list.
Both of these methods work against the internal list of Customers retrieved from the server as follows:
private Task<IEnumerable<Customer>> LoadCustomersAsync()
{
var tcs = new TaskCompletionSource<IEnumerable<Customer>>();
try
{
// GetAsync returns Task<HttpResponseMessage>
Client.GetAsync(uri).ContinueWith(task =>
{
if (task.IsCanceled)
{
tcs.SetCanceled();
}
else if (task.IsFaulted)
{
tcs.SetException(task.Exception);
}
else
{
// Convert HttpResponseMessage to desired return type
var response = task.Result;
var list = response.Content.ReadAs<IEnumerable<Customer>>();
tcs.SetResult(list);
}
});
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
The Client class is a custom version of the HttpClient class from the WCF Web API (now ASP.NET Web API) because I am working in Silverlight and they don't have an SL version of their client assemblies.
After all that background, here's my problem:
All of the methods in the CustomerService class use the list returned by the asynchronous LoadCustomersAsync method; therefore, any calls to these methods should wait (asynchronously) until the LoadCustomers method has returned and the appopriate logic executed on the returned list.
I also only want one call made from the client (in LoadCustomers) at a time. So, I need all of the calls to the public methods to wait on the same internal task.
To review, here's what I need to figure out how to accomplish:
Any call to FindCustomersInArea and GetCustomerByName should return a Task that waits for the LoadCustomersAsync method to complete. If LoadCustomersAsync has already returned (and the cached list still valid), then the method may continue immediately.
After LoadCustomersAsync returns, each method has additional logic required to convert the list into the desired return value for the method.
There must only ever be one active call to LoadCustomersAsync (of the GetAsync method within).
If the cached list expires, then subsequent calls will trigger a reload (via LoadCustomersAsync).
Let me know if you need further clarification, but I'm hoping this is a common enough use case that someone can help me work out the logic to get the client working as desired.
Disclaimer: I'm going to assume you're using a singleton instance of your HttpClient subclass. If that's not the case we need only modify slightly what I'm about to tell you.
Yes, this is totally doable. The mechanism we're going to rely on for subsequent calls to LoadCustomersAsync is that if you attach a continuation to a Task, even if that Task completed eons ago, you're continuation will be signaled "immediately" with the task's final state.
Instead of creating/returning a new TaskCompletionSource<T> (TCS) every time from the LoadCustomerAsync method, you would instead have a field on the class that represents the TCS. This will allow your instance to remember the TCS that last represented the call that represented a cache-miss. This TCS's state will be signaled exactly the same as your existing code. You'll add the knowledge of whether or not the data has expired as another field which, combined with whether the TCS is currently null or not, will be the trigger for whether or not you actually go out and load the data again.
Ok, enough talk, it'll probably make a lot more sense if you see it.
The Code
public class CustomerService
{
// Your cache timeout (using 15mins as example, can load from config or wherever)
private static readonly TimeSpan CustomersCacheTimeout = new TimeSpan(0, 15, 0);
// A lock object used to provide thread safety
private object loadCustomersLock = new object();
private TaskCompletionSource<IEnumerable<Customer>> loadCustomersTaskCompletionSource;
private DateTime loadCustomersLastCacheTime = DateTime.MinValue;
private Task<IEnumerable<Customer>> LoadCustomersAsync()
{
lock(this.loadCustomersLock)
{
bool needToLoadCustomers = this.loadCustomersTaskCompletionSource == null
||
(this.loadCustomersTaskCompletionSource.Task.IsFaulted || this.loadCustomersTaskCompletionSource.Task.IsCanceled)
||
DateTime.Now - this.loadCustomersLastCacheTime.Value > CustomersService.CustomersCacheTimeout;
if(needToLoadCustomers)
{
this.loadCustomersTaskCompletionSource = new TaskCompletionSource<IEnumerable<Customer>>();
try
{
// GetAsync returns Task<HttpResponseMessage>
Client.GetAsync(uri).ContinueWith(antecedent =>
{
if(antecedent.IsCanceled)
{
this.loadCustomersTaskCompletionSource.SetCanceled();
}
else if(antecedent.IsFaulted)
{
this.loadCustomersTaskCompletionSource.SetException(antecedent.Exception);
}
else
{
// Convert HttpResponseMessage to desired return type
var response = antecedent.Result;
var list = response.Content.ReadAs<IEnumerable<Customer>>();
this.loadCustomersTaskCompletionSource.SetResult(list);
// Record the last cache time
this.loadCustomersLastCacheTime = DateTime.Now;
}
});
}
catch(Exception ex)
{
this.loadCustomersTaskCompletionSource.SetException(ex);
}
}
}
}
return this.loadCustomersTaskCompletionSource.Task;
}
Scenarios where the customers aren't loaded:
If it's the first call, the TCS will be null so the TCS will be created and customers fetched.
If the previous call faulted or was canceled, a new TCS will be created and the customers fetched.
If the cache timeout has expired, a new TCS will be created and the customers fetched.
Scenarios where the customers are loading/loaded:
If the customers are in the process of loading, the existing TCS's Task will be returned and any continuations added to the task using ContinueWith will be executed once the TCS has been signaled.
If the customers are already loaded, the existing TCS's Task will be returned and any continuations added to the task using ContinueWith will be executed as soon as the scheduler sees fit.
NOTE: I used a coarse grained locking approach here and you could theoretically improve performance with a reader/writer implementation, but it would probably be a micro-optimization in your case.
I think you should change the way you call Client.GetAsync(uri). Do it roughly like this:
Lazy<Task> getAsyncLazy = new Lazy<Task>(() => Client.GetAsync(uri));
And in your LoadCustomersAsync method you write:
getAsyncLazy.Value.ContinueWith(task => ...
This will ensure that GetAsync only gets called once and that everyone interested in its result will receive the same task.