Flutter testing: static method I need to mock inside code - flutter

I want to test a method that is responsible for a button tap (let's call it onButtonTap()), one of the first methods is a call to static method from utils file, that returns true of false, depending on set android/ios permissions (or allows user to change permissions by showing dialog that can open application settings). Let's call it checkOrRequestPermissions(). This makes everything behind that code untestable, as I don't know how to test it - I can't mock this class because:
It's not injected anywhere - it's inside utils file
It's static
So for better visualization lets go like this:
Code from file I want to test:
Future<void> onButtonTap(BuildContext context) async {
bool isGranted = await PermissionsUtil.checkOrRequestPermissions([some_args]);
// CODE_A - some code I want to test
}
Code inside PermissionsUtil:
class PermissionsUtil{
static Future<bool> checkOrRequestPermissions([some_args]){
// code for permissions
}
}
So my questions are:
Is there any way I could mock checkOrRequestPermissions() to simply return given value?
How could I make this code testable?

Related

how to add and select color for nodes/tree view items in explorer view in my vscode extension

I have added my own explorer view in my extension.
Here I added nodes/tree view items however I am not finding any way to customize and choose color my tree view items in explorer view.
Any idea how to achieve this?
There should be some way because when some file has error then its color is set to different compared to other open file.
[I assume this is your github issue: Not able to use FileDecorationProvider for tree view item.]
Here is my attempt at using a FileDecorationProvider for a custom TreeView. With the caveat that I am new to typescript and FileDecorations.
If you have seen Support proposed DecorationProvider api on custom views you know there are limitations on using a FileDecorationProvider for coloring TreeItem's - primarily that the decoration/coloration cannot be limited to your treeView - wherever that resourceUri apeears, like in the Explorer, your fileDecoration will be applied. That is very unfortunate but I don't believe there is any way to avoid that for now.
First, in your TreeItem class you will have to give whichever items you want decorated a resourceUri. Like this:
export class TreeTab extends vscode.TreeItem {
constructor( public readonly tab: vscode.Tab, public index: number = 0 ) {
super(tab.label, vscode.TreeItemCollapsibleState.None);
this.tab = tab;
if (tab.input instanceof vscode.TabInputText) {
this.resourceUri = tab.input.uri;
}
}
Ignore the specifics of the code for my extension, the point is:
this.resourceUri = <some vscode.Uri>;
Secondly, this is how I set up my FileDecoration class:
import {window, Tab, TabInputText, Uri, Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, ThemeColor} from 'vscode';
export class TreeFileDecorationProvider implements FileDecorationProvider {
private disposables: Array<Disposable> = [];
private readonly _onDidChangeFileDecorations: EventEmitter<Uri | Uri[]> = new EventEmitter< Uri | Uri[]>();
readonly onDidChangeFileDecorations: Event<Uri | Uri[]> = this._onDidChangeFileDecorations.event;
constructor() {
this.disposables = [];
this.disposables.push(window.registerFileDecorationProvider(this));
}
async updateActiveEditor(activeTab: Tab): Promise<void> {
if (activeTab.input instanceof TabInputText)
this._onDidChangeFileDecorations.fire(activeTab.input.uri);
// filter to get only non-activeTabs
activeTab.group.tabs.map( tab => {
if (!tab.isActive && tab.input instanceof TabInputText)
this._onDidChangeFileDecorations.fire(tab.input.uri);
});
}
async provideFileDecoration(uri: Uri): Promise<FileDecoration | undefined> {
const activeEditor = window.activeTextEditor.document.uri;
if (uri.fsPath === activeEditor.fsPath) {
return {
badge: "⇐",
color: new ThemeColor("charts.red"),
// color: new vscode.ThemeColor("tab.activeBackground"),
// tooltip: ""
};
}
else return null; // to get rid of the custom fileDecoration
}
dispose() {
this.disposables.forEach((d) => d.dispose());
}
}
provideFileDecoration(uri: Uri) does the actual decorating. It finds only certain files and decorates them, and by returning null resets that previously decorated uri (as supplied by the uri argument).
updateActiveEditor() is an exported method that I call in other parts of the extension when I want to change a file decoration. So elsewhere I have this in another file:
import { TreeFileDecorationProvider } from './fileDecorator';
export class EditorManager {
public TreeItemDecorator: TreeFileDecorationProvider;
// and then on a listener that gets triggered when I need to make a change to some things including the FileDecoration for a uri
this.TreeItemDecorator.updateActiveEditor(activeTab);
this.TreeItemDecorator.updateActiveEditor(activeTab); that calls the updateActiveEditor method in the TreeFileDecorationProvider class which calls the this._onDidChangeFileDecorations.fire(<some uri>); method for uri's that need to have the decoration applied and also for uri's that need to have the decoration removed.
this._onDidChangeFileDecorations.fire(<some uri>); will call provideFileDecoration(uri: Uri) where the actual decoration will be applied or removed depending on some state of that uri.
I am sure there is a way to call onDidChangeFileDecorations() directly from another file in your project (if you don't need to do any pre-processing of the uri like I have to do. I just haven't figured out how to construct the argument for that function yet. Perhaps someone will help on that point.
You can see here:
color: new ThemeColor("charts.red"),
// color: new vscode.ThemeColor("tab.activeBackground"),
how a color is chosen - it must be some ThemeColor. The charts theme colors has a few basic colors that are handy to refer to. See theme color references, Charts therein.
The badge option can take up to 2 characters, but as you see I copied/pasted a unicode character for mine and that works.
As I mentioned my FileDecorationProvider is called from an eventListener, but you may not need that for your use case - if decorations do not have to added and removed based on user actions like in my case. So you may be able to call your FileDecorationProvider right from your extension.ts activate() like so:
import * as vscode from 'vscode';
import { TreeFileDecorationProvider } from './fileDecorator';
export async function activate(context: vscode.ExtensionContext) {
new TreeFileDecorationProvider();
}
Other references:
a treeDecorationProvider.ts example
part of the git extension that does file decorations
Custom view decorations in VSCode extension

Navigate to page on start in .NET Maui app

Seems like a simple question, but I haven't been able to find a simple answer. Essentially I want to choose which page in the app to start on based on some stored state. I added a GoToAsync call in the AppShell constructor, but this didn't work--which makes sense because the AppShell hasn't been fully constructed yet.
I found this answer, but it feels like it kind of skirts around the issue:
Maui AppShell - Navigate on Open
Where is the best place to inject some code that will run once on startup and can successfully navigate a .NET Maui app to a chosen page?
After playing around with overrides, it seems like overriding Application.OnStart works! Shell.Current is set at this point and navigation works.
Here's additional code that allows for asynchronous initialization and uses a Loading Page until the initialization is complete:
using MyApp.Services;
using MyApp.UI;
namespace MyApp;
public partial class App : Application
{
ConfigurationProviderService m_configProvider;
public App(ConfigurationProviderService configProvider)
{
m_configProvider = configProvider;
InitializeComponent();
MainPage = new LoadingPage();
}
protected override void OnStart()
{
var task = InitAsync();
task.ContinueWith((task) =>
{
MainThread.BeginInvokeOnMainThread(() =>
{
MainPage = new AppShell();
// Choose navigation depending on init
Shell.Current.GoToAsync(...);
});
});
base.OnStart();
}
private async Task InitAsync()
{
await m_configProvider.InitAsync();
}
}

How to link to another methods in dart comments

I was documenting my code and I wanted to link another method in the same file
I want to refer to that method in a comment so anyone reading my comment can directly jump to that method where my comment refers
Method where I am documenting and I want to link to a method named toggleFavorite in the same file
// To avoid code duplication in [toggleFavorite] method
void _toogleFav(newStatus) {
isFavorite = newStatus;
notifyListeners();
}
This is what my toggleFavorite returns in case you need it
Future<void> toggleFavorite() async {
What I want
Exactly I want this word in my comment [toggleFavorite] to work as a link when I press this I get redirected to this method wherever it is created or used
Use triple /// and [] around the method
/// To avoid code duplication in [toggleFavorite] method
void _toogleFav(newStatus) {
isFavorite = newStatus;
notifyListeners();
}

how to handle multiple `loading` states with redux architecture in Flutter?

How do you guys handle multiple loading states with redux pattern in Flutter?
So here is my case:
I have 3 pages, each page calls a different API and shows a loading HUD while requesting the API.
Sub-Question#1 How do i manage these isLoading states?
If i do it in the AppState , i need to add multiple boolean properties to it, something like:
class AppState {
final bool apiOneIsLoading;
final bool apiTwoIsLoading;
final bool apiThreeIsLoading;
// other properties, bla bla...
}
However, Adding to many properties to the AppState class doesn’t sounds great I guess...
Sub-Question#2 How do I update the UI when the loading state changes?
One solution I come up with is to create actions for both loading and loaded state, like so:
class SomeMiddleware extends MiddlewareClass<AppState> {
#override
void call(Store<AppState> store, dynamic action, NextDispatcher next) {
if (action is CallAPIOneAction) {
store.dispatch(APIOneLoadingAction());
// call api one
api.request().then((result){
store.dispatch(APIOneLoadedAction())
})
}
}
}
But if I do this, I need to create 2 extra actions for each API call, is this a good idea? is it okay to change or send new actions in middleware class on the fly?
Please let me know if you have a good solution, thanks!

Called OnResume Method From Activity to Fragment is not Updating Variables

I have an issue which I couldn't figure out for hours,
I have a fragments inside an activity, and sometimes I call the fragment with the codes below:
newsFeedFragment fragment = new newsFeedFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(getSupportFragmentManager().findFragmentById(R.id.fragment_container));
fragmentTransaction.hide(getSupportFragmentManager().findFragmentByTag("notifications_fragment"));
fragmentTransaction.show(getSupportFragmentManager().findFragmentByTag("news_feed_fragment"));
fragmentTransaction.addToBackStack(null);
fragment.onResume();
fragmentTransaction.commit();
As the onResume is not called while showing the fragments I use "fragment.onResume();" in the code below. And when the fragment is shown, the onResume is called. However, I try to update a variable in the onResume method, but it is not updated with the code below. When ever the onResume is called, I see "1" as the result in the log, however I was expecting it to increase by 1 every time. Is there a way to make it work?
int refreshNotificationVar = 0; //in the main class
#Override
public void onResume(){
super.onResume();
refreshNotificationVar = refreshNotificationVar + 1;
System.out.println(refreshNotificationVar);
}
You cannot rely on instance variables in case of onPause and onResume; you can rely on static variables to some extent; you can use onSaveInstanceState; or use a Singleton class to store variable values; or store in shared preferences; or maybe store in a database depending on your needs. In your case, I would use a Singleton class to store the values and get/set them in onPause/onResume.