I'm using karma with qUnit (after following this tutorial) to test my Ember application. It's mostly going well, however I've run into a problem that doesn't make sense.
Given the 2 following tests:
test('can get to products', function() {
visit('/products/')
.then(function() {
ok(find('*'));
});
});
test('can get to catalogues', function() {
visit('/products/catalogues')
.then(function() {
ok(find('*'));
});
});
The first will run fine. The test runner gets to /products and finds something.
However, the second test returns an error in the console:
Error: Assertion Failed: You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run
I turned on transition logs, and the test runner is visiting products.catalogues.index before throwing the error.
Any ideas with this? Or is it simply a bug inside ember's testing tools?
Both are valid routes defined inside the router...
The last part of the error holds the key to how to fix this problem. You have to make sure that any code that make async calls is wrapped in Ember.run. This includes things as simple as the create and set methods.
If you have something like
App.ProductsRoute = Ember.Route.extend({
model: function() {
return [
Ember.Object.create({title: "product1"}),
Ember.Object.create({title: "product2"})
]
}
});
refactor it to
App.ProductsRoute = Ember.Route.extend({
model: function() {
return [
Ember.run( Ember.Object, "create", {title: "product1"} ),
Ember.run( Ember.Object, "create", {title: "product2"} )
]
}
});
or
App.ProductsRoute = Ember.Route.extend({
model: function() {
return Ember.run(function() {
return [
Ember.Object.create({title: "product1"}),
Ember.Object.create({title: "product2"})
]
});
}
});
If you posted your /products code it would be easier to give a more specific answer.
Related
Here's a simple example on the forgot password reset page of my app, I would want to bypass the server side and just have the password reset to succeed on click so I would write a test and use the custom test store like so:
const customStore = {
state() {
return {
Authentication: {
passwordResetSuccess: false,
},
};
},
mutations: {
SET_RESET_PASSWORD_SUCCESS(state) {
state.Authentication.passwordResetSuccess = true;
},
},
actions: {
forgotPasswordResetPassword() {
this.commit('SET_RESET_PASSWORD_SUCCESS');
},
},
};
Then I could include the custom store in my beforeEach() and it worked great. I've tried everything I can think of to get this to work with pinia, but it doesn't seem to work.
I'm using jest along with vue/test-utils.
I basically tried just creating the test pinia store, but I can't figure out how to get the component to use the custom test store.
const useCustomStore = defineStore('AuthenticationStore', {
state: () => ({
passwordResetSuccess: false,
}),
actions: {
forgotPasswordResetPassword() {
this.passwordResetSuccess = true;
},
},
});
const authenticationStore = useCustomStore();
I can't directly add it as a plugin because it can't find an active instance of pinia.
I went through this guide: https://pinia.vuejs.org/cookbook/testing.html#unit-testing-a-store
and I also tried using jest mock as described here: https://stackoverflow.com/a/71407557/4697639
But it still failed.
If anyone has any idea how to create a custom store that can be used by the component and actually hits the custom actions, I could really use some help figuring this out. Thank you!!
Tao mentioned in the comments that this isn't a good way to do unit tests. I will mark this as resolved and fix how I do the testing.
I am trying to run a piece of code in the .then section of stripe.redirectTocheckout function. But it redirects me to the successfulUrl part before showing any response/result in the .then({}) and hence the code in the .then section does not run. Kindly help me. I am stuck here from a long time. Thank you.
stripe.redirectToCheckout({
items: [{ sku: 'abcssdd', quantity: 1 }],
successUrl:'https://your-website.com/congratulation',
cancelUrl: 'https://your-website.com/canceled',
})
.then(function (result) {
if (result.error) {
var displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
console.log("Inside Then");
})
The then option is there in case it fails. If it's not failing, there is no reason to show error.
It's a little confusing, IMHO, because then() is usually associated with success and catch() with the error., but note the comments form their docs below:
const stripe = Stripe('pk_test_TYauvdEDq54NiTpjx');
stripe.redirectToCheckout({
items: [
// Replace with the ID of your SKU
{sku: 'sku_123', quantity: 1}
],
successUrl: 'https://your-website.com/success',
cancelUrl: 'https://your-website.com/canceled',
}).then(({error}) => {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `error.message`.
});
src: https://stripe.com/docs/stripe-js/reference#stripe-redirect-to-checkout
I am using Vue.js for a CRUD system, tracking a number of different domain classes, such as Customer, Product, etc. I have a validation mixin which I use in each editor component (e.g, CustomerDetail, ProductDetail). Because I would like common behaviour when a user moves away from the page without saving, I'd like to be able to have a method in my validation mixin which I can call in 'beforeRouteLeave'. The method I have come up with is this:
checkOnLeave(obj,message,confirmText="Leave",cancelText="Continue Editing",next){
if (this.isDirty(obj)) { //isDirty checks whether object has been changed
bootbox.confirm({
message: message,
buttons: {
confirm: {
label: confirmText,
},
cancel: {
label: cancelText,
}
},
callback: function (result) {
if (result) {
next();
} else {
next(false);
}
}
});
} else {
next();
}
}
When I try to use this, though, it doesn't have any idea what to do with 'next'. Clearly this is something from vue-router which it is unaware of. So how can I make my mixin vue-router aware so that I can use this?
Red herring alert. It actually works fine as is - it must have been a delay in compiling which caused the problem before (it happens from time to time with 'npm run dev', the compile occasionally doesn't kick in).
If I change the order of my Ember/Qunit tests, they pass. Why is that, or what can I do to avoid it?
Edit: I notice that the Qunit tests run in a more or less random order (whichever is ready first?), regardless, when TEST B follows TEST A, it is failing.
It seems that either App.reset() isn't fully resetting or there is some async issue I'm not seeing.
spec
module("Integration Tests", {
setup: function() {
console.log('reset');
Encompass.reset();
}
});
test("TEST A", function() {
visit("/workspaces").then(function() {
ok(true);
});
});
test("TEST B", function() {
visit('/workspaces/1/submissions/1').then(function() {
ok(find('li[title="Kyle Folder 1"]').length, "the folder is there");
});
});
I have both versions of the test online.
A then B, B fails
B then A, both pass
This is using the fixture adapter with a bunch of models (possibly not all the correct relations, but I still expect the tests to be consistent regardless of order)
App.reset() resets the ember application itself, it doesn't reset Ember Model/Data.
You'll need to use unloadAll for Ember Data:
this.store.unloadAll('post');
For Ember Model you'll use clearCache:
App.Post.clearCache();
Have you tried allowing the visit to resolve before running ok on test A?
test("TEST A", function() {
visit("/workspaces").then( function(){
ok(true);
});
});
Anyone have any good examples of testing Ember data in your own app?
I'm starting to build an app using the Fixtures adapter, which is great. But I want to test my models and make sure everything works properly as I build.
I have QUnit setup and running, but I don't want to write the server side in order to verify that the Data Model makes a call. I'd like to mock out the Adapter and just see if the find method is called and return a new object from it. I'll worry about the server side implementation later.
Any ideas?
This is what I have so far (that doesn't work):
test('MyModel should call find', 1, function(){
App.TestAdapter = DS.Adapter.extend({
find: function(store, type, id){
ok(true, 'calls the find method');
console.log('find: ', type, id);
}
});
App.Store = DS.Store.extend({
adapter: 'App.TestAdapater'
});
myModel = App.MyModel.createRecord({
name: 'Test',
period: 0
});
// method that should call .find
myModel.currentObject();
});
I ended up going with Konacha.
The biggest part was:
before(function() {
Ember.run(function() {
App.initialize();
});
});
afterEach(function() {
Ember.run(function() {
App.reset();
});
});