Flutter: BloC inject mocks in app testing - flutter

I'm trying to create a flutter app using flutter_bloc, firebase auth and firestore.
I following flutter_firebase_login example which is truly amazing for all the testing coverage.
I would like to go one step further. Once the use is authenticated, I want to load the user profile from firestore, then actually display the app. (In practice, once the profile is loaded, I will have to do new firestore lookups that will depend on the profile info).
So I kind of have a chain of events:
Authenticate -> Load profile for user "uid" -> Load data depending on profile.
I'm wondering what is the good way to do that which still allows me to test my full app using mocks only.
The example injects the authenticationRepository into the App class then we can inject it in the test. My problem now is that, once the user is logged in and we redirect to the HomePage widget, this widget will have to create a new provider. But if it does create a new one, then I can't inject it anymore.
What is the good practice there? Here are the few options I've been considering:
Inject all the providers in the main()
I guess this would be the simplest solution. Though since those providers are kind of chained, I would have to pass the context data to every call on the "sub" providers, the context from the previous one. For instance:
ProfileRepository {
... getProfile(uid);
}
DataRepository {
... getData(... profile)
}
Dynamically build the providers
Ideally, I would like to not need those extra params in my providers and instead build my providers with those context values. Example:
ProfileRepository {
ProfileRepository(uid)...
... getProfile();
}
DataRepository {
DataRepository(profile)...
... getData()
}
So each time the uid changes, we would create a new provider for the profile and for each profile change we would create a new data provider.
This will simplify the calls in my app to not have to load the profile to get the data. The sub widgets just need to get the current provider and call the functions without the depending contexts.
Though just calling the constructor from my widgets would create problems for the tests DI which means I would have to create provider factories that I could then inject. And from the tests I would pass mock factories and in my main(), the prod factories.
Adding a state to my providers
I would inject all my factories in the main but instead of constructing them using the uid or the profile. Pseudo code:
ProfileRepository {
setUid(uid)...
... getProfile();
}
DataRepository {
setProfile(profile)...
... getData(... otherParams)
}
Each time the user changes or the profile changes, I just call the setters. That way I don't need to pass provider factories from the main.
Note
I considered to wrap the AuthenticationRepository into a UserProfileRepository which would remove one step here but for the data, this would not work.
I'm not sure what is the good practice here and would love to get feedback.
Thank you in advance!

Related

How to simulate the behaviour when the user loads the app from the URL in the browser's address bar

I'm writing a Flutter web application and I want to write a test on the behavior when the user loads the app when he types the URL in the browser's address bar.
For example I would like my test to behave as if the user typed /my/path.
How can I do that?
If you look at the class PlatformDispatcher (which olds a singleton instance .instance) you can see a getter defaultRouteName.
The route or path that the embedder requested when the application was launched.
This will be the string "/" if no particular route was requested.
So when your user starts your application with the url /my/path, PlatformDispatcher.instance.defaultRouteName with be equal to '/my/path'.
How to mock it?
You can also access the PlatformDispatcher.instance from WidgetsBinding.instance.platformDispatcher and if you read the doc of the getter platformDispatcher, you'll read:
A subclass of BindingBase, such as TestWidgetsFlutterBinding, can override this accessor to return a different ui.PlatformDispatcher implementation.
In the context of a testWidgets
testWidgets('', (WidgetTester test) async {});
tester.binding gives you access to the TestWidgetsFlutterBinding which is the binding used by widgets library tests. In this test binding, the platformDispatcher is overridden and a TestPlatformDispatcher with a setter defaultRouterNameTestValue that you can use to mock the defaultRouteName getter.
TL;DR
You can use:
tester.binding.platformDispatcher.defaultRouteNameTestValue = '/my/path'
to test the behavior when the user loads the app when he types the URL /my/path in the browser's address bar.

Asp .Net Core 5 Identity - How to fetch a user?

In the new SPA (react and angular) web templates for .Net core 5. I'd like to fetch the current logged in User. However, when I try to get a user in the controller the User doesn't have anything populated.
Does anyone know how to achieve this with the new Identity Classes?
I've made a repo of the vanilla reactJS template, the only thing I changed is the line highlighted in my screenshot below to show there's no user set.
I've done a bit of googling and these pages are all I could find on the topic, unfortunately, they don't give enough detail for me to be able to implement anything practical.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-5.0
Backend:
ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);
On the frontend if you need yo access it
//with UserManager
UserManager<ApplicationUser> UserManager
#{
var user = await UserManager.GetUserAsync(User);
}
// with SignInManager
SignInManager<ApplicationUser> SignInManager
#if (SignInManager.IsSignedIn(User))
To answer my own question.
In order to populate the User detail in the HttpContext you have 1 of 2 routes. Either change
services.AddDefaultIdentity<IdentityUser>();
to
services.AddIdentity<IdentityUser, IdentityRole>();
or you can continue to use the Core Identity
services.AddIdentityCore<IdentityUser>();
but then you also need to implement your own Microsoft.AspNetCore.Identity.ISecurityStampValidator and add it as transient services.AddTransient<ISecurityStampValidator, MyValidator>();
Your MyValidator implementation will be responsible for validating the cookie. You can see the default implementation here on github
Edit: Under the hood services.AddDefaultIdentity<IdentityUser>(); uses services.AddIdentityCore<IdentityUser>();. I feel like its importatnt to know this.

Best way to use BLoC as global state management

So I have a BLoC which I need to access globally through my app - CurrentUserBloc and its purpose is to hold data of currently logged in user. It can hold some states like CurrentUserWaiting, CurrentUserReady, CurrentUserError etc. Some of them hold user instance - like CurrentUserReady, and some don't - like CurrentUserWaiting. Now I need to access this user data in order to send an event to another BLoC. For example I want to post a photo and I need userId of currently logged in user to do this. But I can't just use BlocProvider.of<CurrentUserCubit>(context).state.user to get user data because some of this bloc's states - like CurrentUserWaiting - don't store user property and compiler won't take this.
I get around it by creating abstract state class CurrentUserWithUserInstance and extending it in states that hold user property. Then I just access state like this:
final currentState = BlocProvider.of<CurrentUserCubit>(context).state
as CurrentUserWithUserInstance;
Then I get user property from this and use it to add event in another BLoC.
I was wondering what would be a better way to do this. I need to access user data in multiple places in the app and I don't know if this is a good approach. I know I could use just one state class with all properties and then change it by copyWith method. By that doesn't really seem that good to me.
How do you store and access global state using BLoC?

Autofac OWIN web api - load dependency based on request

How I can load a service dependency based on the route parameter?
My requirement is different, but I'll try to use a simple example.
A user can select the shipping provider (UPS, Fedex...) and the information is as part of the request model or route. Based on the route, I need to load the service class.
How it can be done in Autofac OWIN? Help on this will be appreciated
When you use the Autofac's OWIN integration, each request creates a new lifetime scope in which the current IOwinContext is registered, as you can see here.
You could then delegate the creation of your service to a factory that would take a dependency on IOwinContext.
public class MyServiceFactory
{
private readonly IOwinContext _context;
public MyServiceFactory(IOwinContext context)
{
_context = context;
}
public IService Create()
{
// inspect the context and determine which service you need
// you could return, dependending on, let's say, the URL
// - UpsService()
// - FedexService()
}
}
One thing you'll need to make sure is that you register your factory as InstancePerLifetimeScope since the IOwinContext will be different for each request.
Do you need to work at the OWIN layer, though? It will make things harder, and possibly a bit hacky, since OWIN is really just the HTTP layer, so there's no such thing as route data.
If you use ASP.NET Web API, you could base the factory on the current HttpRequestMessage if you use the RegisterHttpRequestMessage extension method.
You can then access route data through request.GetRequestContext().RouteData. Note that GetRequestContext is an extension method in the System.Net.Http namespace.
If you use ASP.NET MVC, you can register the AutofacWebTypesModule in the container, itself registering quite a few types in the container.
One of those is HttpRequestContext which has a RouteData property, so you can inject this one in the factory and apply your logic.

User roles in GWT applications

I'm wondering if you could suggest me any way to implement "user roles" in GWT applications. I would like to implement a GWT application where users log in and are assigned "roles". Based on their role, they would be able to see and use different application areas.
Here are two possible solution I thought:
1) A possible solution could be to make an RPC call to the server during onModuleLoad. This RPC call would generate the necessary Widgets and/or place them on a panel and then return this panel to the client end.
2) Another possible solution could be to make an RPC call on login retrieving from server users roles and inspecting them to see what the user can do.
What do you think about?
Thank you very much in advance for your help!
Another way is to host your GWT app in a JSP page. Your JSP might contain a snippet of code like this
<script type="text/javascript">
var role = unescape("${role}");
</script>
Where ${role} is expression language expanded from value you computed from the associated servlet / controller and exposed to the JSP.
When your GWT app runs in the browser, the value will be filled out. Your GWT app can easily call out into JS to obtain this value from a native method call, e.g.
public native String getRole() { /*-{ return $wnd.role; }-*/;
So your module could invoke getRole(), test the value and do what it likes to hide / show elements.
Obviously your backend should also enforce the role (e.g. by storing it in the session and testing it where appropriate) since someone could run the page through a JS debugger, setting breakpoint or similar that modifies the value before it is evaluated allowing them to access things they shouldn't be accessing.
Following scenario works for me:
GWT app is behind security constraint.
On module load I make RPC call to retrieve roles from the container. I store them in main GWT module's class as static field, to make it easy for other classes to use it.
Each widget (especially menu) can use roles (e.g. call Main.getRoles()) and construct itself according to roles. I don't pass roles in constructor. Each widget knows how to behave depending on role.
If it's crucial to not only hide things but also enforce them you can use container security and check roles and rights while invoking business methods.
While using GIN you can also create singleton class to store roles retrieved during login and inject it wherever you need it.