How can I catch an Exception inside a Controller for a Livewire Component - laravel-livewire

I am trying to catch a QueryException inside a livewire Controller. I want to render a different view when the database is not connected. This seems not to work since what am trying to fetch from the database is returned as null. The component is rendered regardless of whether I catch the Exception or not.
This is my function for fetching records and I have a view(dbConnection) inside the errors folder. I expect the view dbConnection inside the errors folder to be returned when the database is not connected.
class FetchPosts extends Component
{
use WithPagination;
public $featured = false;
public $votes = false;
public $latest = false;
public function fetchRecords()
{
try{
$topics = Topics::withCount(['topicComments', 'upVotes', 'downVotes']);
if ($this->featured) {
$topics->orderBy('topic_comments_count', 'desc')->orderBy('up_votes_count', 'desc');
} elseif ($this->votes) {
$topics->orderBy('up_votes_count', 'desc');
}
return $topics->orderBy('id', 'desc')->paginate(10);
}
catch(Throwable $e){
return view('errors.dbConnection');
}
}
public function render()
{
return view('livewire.fetch-posts', ['topics' => $this->fetchRecords()]);
}
}
After running the code:- this is the error I get
Call to a member function count() on string.
This occurs from this line
#if($topics->count())

Related

Testing Laravel Livewire sorting component

I'm trying to test a sort by call for a table, The sort by works in practice but I cannot generate a failing test, my test always passes so I'm not testing it correctly.
Steps to Reproduce:
This is the test:
Livewire::test(Roles::class)
->call('sortBy', 'blah')
->assertSet('sortField', 'blah')
->call('roles')
->assertStatus(200);
the param blah should match a database column, I don't have a column called blah so should fail, but it passes.
the component:
class Roles extends Component
{
use WithPagination;
public $paginate;
public $query;
public $sortField = 'name';
public $sortAsc = true;
protected $queryString = ['query'];
public function render()
{
abort_if_cannot('view_roles');
return view('livewire.roles.roles');
}
public function builder()
{
return Role::orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc');
}
public function sortBy($field)
{
if ($this->sortField === $field) {
$this->sortAsc = ! $this->sortAsc;
} else {
$this->sortAsc = true;
}
$this->sortField = $field;
}
public function roles()
{
$query = $this->builder();
if ($this->query) {
$query->where('name', 'like', '%'.$this->query.'%');
}
return $query->paginate($this->paginate);
}
public function deleteRole($id): void
{
abort_if_cannot('delete_roles');
$this->builder()->findOrFail($id)->delete();
$this->dispatchBrowserEvent('close-modal');
}
}
Are you using the latest version of Livewire: v2.3.6
If I attempt to run:
wire:click.prevent="sortBy('blah')
Then I do get an SQL error as expected.
Anyone know how I can update my test to actually see there's an error.

How can i write unit test for this actionfilter

public MyContext _db;
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (_db == null || !_db.ChangeTracker.HasChanges())
{
return;
}
try
{
_db.SaveChanges();
}
catch
{
}
}
This is my action filter for my wep api project. _db context object injected to this filter by per request. My point is here to call SaveChanges() method once after all processing done in service layers. My problem is how can test this filter? How can i mimic exception case that can happen in any controler or service layer and when exception throws saveChanges() never called? How can i setup the case that exception occurred in any place inside application?
I have been doing the same, last week, for my WebAPI 2 action filter.
I have an action filter that validates my ModelState and in case of any error it throws an error list with 200 HTTPcode.
The action looks like this:
public class ModelValidationActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
{
actionContext.Response = ...
}
}
}
UNIT TEST
var httpControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri")
{
Content = new ObjectContent(typeof(MyModel),
new MyModel(), new JsonMediaTypeFormatter())
},
RequestContext = new HttpRequestContext()
};
httpControllerContext.Request = new HttpRequestMessage();
httpControllerContext.Request.SetConfiguration(new HttpConfiguration());
var httpActionContext = new HttpActionContext { ControllerContext = httpControllerContext };
var filter = new ModelValidationActionFilterAttribute();
httpActionContext.ModelState.AddModelError("*", "Invalid model state");
// act
filter.OnActionExecuting(httpActionContext);
// assert
httpActionContext.Response.ShouldNotBe(null);
httpActionContext.Response.ShouldBeOfType(typeof (HttpResponseMessage));
var result = httpActionContext.Response.Content.ReadAsStringAsync().Result;
BaseServiceResponse<object> resultResponse =
JsonConvert.DeserializeObject<BaseServiceResponse<object>>(result);
resultResponse.Data.ShouldBe(null);
resultResponse.Messages.Count.ShouldBe(1);
resultResponse.Messages.First().Description.ShouldBe("Invalid model state");
In your case you need to Mock DB context using IDbContext interface - see here: http://aikmeng.com/post/62817541825/how-to-mock-dbcontext-and-dbset-with-moq-for-unit
If an unhandled exception occurs while executing the request then the Exception property on actionExecutedContext will contain the exception. This is part of the framework, and not something you need to test. In your tests you can simple set the Exception property manually and assert that the attribute takes the correct action.
[Fact]
public void Saves_data_on_failure()
{
var mockDbContext = new Mock<IDbContext>();
var myAttribute = new MyAttribute(mockDbContext.Object);
var executionContext = new HttpActionExecutedContext
{
Exception = new Exception("Request failed.")
};
myAttribute.OnActionExecuted(executionContext);
mockDbContext.Verify(d => d.SaveChanges());
}
You might also want to consider whether or not you want to save data for all types of exception. The data might be in an invalid/unknown state.

Change Activity into Fragment

I am quite new at Android.
So I am a bit confused of working with fragments.
I have found a very great tutorial.
So I have working code. But it is the layout oft a normal activity.
Then I tried to include it into a navigation drawer.
So the list view with data will only be shown when the menu item has been selected.
On the fragment View there is a never ending loading Dialog.
While debugging I have figured out that the code loads still the data and inserts it into feedItems.
So feedItems is filled correctly.
Now after listAdapter.notifyDataSetChanged() there happens nothing.
So here that is my code:
public class FragmentNews extends ListFragment {
private static final String TAG = FragmentNews.class.getSimpleName();
private ListView listView;
private FeedListAdapter listAdapter;
private List<FeedItem> feedItems;
private String URL_FEED = "http://address.com";
public FragmentNews(){}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
loadDataForNews();
}
private void loadDataForNews(){
listView = this.getListView();
feedItems = new ArrayList<FeedItem>();
listAdapter = new FeedListAdapter(getActivity(), feedItems);
listView.setAdapter(listAdapter);
// We first check for cached request
Cache cache = AppController.getInstance().getRequestQueue().getCache();
Entry entry = cache.get(URL_FEED);
if (entry != null) {
// fetch the data from cache
try {
String data = new String(entry.data, "UTF-8");
try {
parseJsonFeed(new JSONObject(data));
} catch (JSONException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
// making fresh volley request and getting json
JsonObjectRequest jsonReq = new JsonObjectRequest(Method.GET,
URL_FEED, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
VolleyLog.d(TAG, "Response: " + response.toString());
if (response != null) {
parseJsonFeed(response);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
});
// Adding request to volley request queue
AppController.getInstance().addToRequestQueue(jsonReq);
}
}
// List View Feed
private void parseJsonFeed(JSONObject response) {
try {
JSONArray feedArray = response.getJSONArray("feed");
for (int i = 0; i < feedArray.length(); i++) {
JSONObject feedObj = (JSONObject) feedArray.get(i);
FeedItem item = new FeedItem();
item.setId(feedObj.getInt("id"));
item.setName(feedObj.getString("name"));
// Image might be null sometimes
String image = feedObj.isNull("image") ? null : feedObj
.getString("image");
item.setImge(image);
item.setStatus(feedObj.getString("status"));
item.setProfilePic(feedObj.getString("profilePic"));
item.setTimeStamp(feedObj.getString("timeStamp"));
// url might be null sometimes
String feedUrl = feedObj.isNull("url") ? null : feedObj
.getString("url");
item.setUrl(feedUrl);
feedItems.add(item);
}
// notify data changes to list adapater
listAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Can the problem be that the inflater of listAdapter is null?
Thanks for help!
Sometimes listAdapter.notifyDataSetChanged() does not work properly.
Try removing
listAdapter = new FeedListAdapter(getActivity(), feedItems);
listView.setAdapter(listAdapter);
from loadDataForNews() and adding in
place of listAdapter.notifyDataSetChanged();

RavenDB keeps throwing a ConcurrencyException

I keep getting a ConcurrencyException trying to update the same document multiple times in succession. PUT attempted on document '<id>' using a non current etag is the message.
On every save from our UI we publish an event using MassTransit. This event is sent to the subscriberqueues, but I put the Eventhandlers offline (testing offline subscribers). Once the eventhandler comes online the queue is read and the messages are processed as intended.
However since the same object is in the queue multiple times the first write succeeds, the next doesn't and throws this concurrencyexception.
I use a factory class to have a consistent IDocumentStore and IDocumentSession in all my applications. I specifically set the UseOptimisticConcurrency = false in the GetSession() method.
public static class RavenFactory
{
public static IDocumentStore CreateDocumentStore()
{
var store = new DocumentStore() { ConnectionStringName = "RavenDB" };
// Setting Conventions
store.Conventions.RegisterIdConvention<MyType>((db, cmd, e) => e.MyProperty.ToString());
store.Conventions.RegisterAsyncIdConvention<MyType>((db, cmd, e) => new CompletedTask<string>(e.MyProperty.ToString()));
// Registering Listeners
store
.RegisterListener(new TakeNewestConflictResolutionListener())
.RegisterListener(new DocumentConversionListener())
.RegisterListener(new DocumentStoreListener());
// Initialize and return
store.Initialize();
return store;
}
public static IDocumentSession GetSession(IDocumentStore store)
{
var session = store.OpenSession();
session.Advanced.UseOptimisticConcurrency = false;
return session;
}
}
The eventhandler looks like this. The IDocumentSession gets injected using Dependency Injection.
Here is the logic to get an instance of IDocumentSession.
private static void InitializeRavenDB(IUnityContainer container)
{
container.RegisterInstance<IDocumentStore>(RavenFactory.CreateDocumentStore(), new ContainerControlledLifetimeManager());
container.RegisterType<IDocumentSession, DocumentSession>(new PerResolveLifetimeManager(), new InjectionFactory(c => RavenFactory.GetSession(c.Resolve<IDocumentStore>())));
}
And here is the actual EventHandler which has the ConcurrencyException.
public class MyEventHandler:Consumes<MyEvent>.All, IConsumer
{
private readonly IDocumentSession _session;
public MyEventHandler(IDocumentSession session)
{
if (session == null) throw new ArgumentNullException("session");
_session = session;
}
public void Consume(MyEvent message)
{
Console.WriteLine("MyEvent received: Id = '{0}'", message.MyProperty);
try
{
_session.Store(message);
_session.SaveChanges();
}
catch (Exception ex)
{
var exc = ex.ToString();
// Deal with concurrent writes ...
throw;
}
}
}
I want to ignore any concurrencyexception for now until we can sort out with the business on how to tackle concurrency.
So, any ideas why I get the ConcurrencyException? I want the save to happen no matter whether the document has been updated before or not.
I am unfamiliar with configuring Unity, but you always want Singleton of the IDocumentStore. Below, I have coded the Singleton out manually, but I'm sure Unity would support it:
public static class RavenFactory
{
private static IDocumentStore store;
private static object syncLock = new object();
public static IDocumentStore CreateDocumentStore()
{
if(RavenFactory.store != null)
return RavenFactory.store;
lock(syncLock)
{
if(RavenFactory.store != null)
return RavenFactory.store;
var localStore = new DocumentStore() { ConnectionStringName = "RavenDB" };
// Setting Conventions
localStore .Conventions.RegisterIdConvention<MyType>((db, cmd, e) => e.MyProperty.ToString());
localStore .Conventions.RegisterAsyncIdConvention<MyType>((db, cmd, e) => new CompletedTask<string>(e.MyProperty.ToString()));
// Registering Listeners
localStore
.RegisterListener(new TakeNewestConflictResolutionListener())
.RegisterListener(new DocumentConversionListener())
.RegisterListener(new DocumentStoreListener());
// Initialize and return
localStore.Initialize();
RavenFactory.store = localStore;
return RavenFactory.store;
}
}
// As before
// public static IDocumentSession GetSession(IDocumentStore store)
//
}

Testing WebSecurity.Login() problems

I'm trying to test my ASP.NET MVC4 Application within Visual Studio and I am running into problems when testing WebSecurity.Login().
It seems to work perfectly when running my application but throws out an error when testing.
Method to test:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(HomeModels.LoginModel model)
{
if (ModelState.IsValid)
{
try
{
var username = model.Username;
var password = model.Password;
if (WebSecurity.Login(username, password, true))
{
if (Roles.Provider.IsUserInRole(username, "admin"))
{
return RedirectToAction("AdminHome");
}
else if (Roles.Provider.IsUserInRole(username, "user"))
{
return RedirectToAction("LoginSuccessful");
}
}
else
{
//String errorMessage = "Login was not successful.";
}
}
catch (MemberAccessException e)
{
ModelState.AddModelError("", e);
}
}
return View(model);
}
Test Method:
[TestMethod]
public void TestLoginAdminSuccessfulView()
{
HomeController controller = new HomeController();
Ecommerce.Models.HomeModels.LoginModel login = new Ecommerce.Models.HomeModels.LoginModel();
login.Username = "sgupta";
login.Password = "sgupta2189";
var result = (RedirectToRouteResult) controller.Login(login);
Assert.AreEqual("AdminHome", result.RouteName);
}
Error Message:
Test method EcommerceUnitTests.Controllers.HomeControllerTest.TestLoginAdminSuccessfulView threw exception:
System.InvalidOperationException: To call this method, the "Membership.Provider" property must be an instance of "ExtendedMembershipProvider".
Error Stack Trace:
WebMatrix.WebData.WebSecurity.VerifyProvider()
WebMatrix.WebData.WebSecurity.Login(String userName, String password, Boolean persistCookie)
Ecommerce.Controllers.HomeController.Login(LoginModel model)
EcommerceUnitTests.Controllers.HomeControllerTest.TestLoginAdminSuccessfulView()
copy the working web.config to app.config in the project containing your tests.
Make sure your Test project references assembly that is / contains your custom member provider.
If the main project is working, check what references it has.
I ended up restructuring it all and using ASP.NET's default membership provider.