How to use Cypress tests with vue axios? - vue.js

I have some vue ant-design code
<a-form...>
<button #click="submit"
</a-form>
<script>
...
methods: {
submit() {
return this.axios({
method: "POST",
data: this.form
}).then(...)
}
}
i want to create e2e test, which type form and submit this by click button.
...
cy.get("[data-testid=submit-form").click();
but how i can wait when submit axios will call then-callback?
cy.wait() is a bad solution for this.
use cy.request it is not 100% user case, its javascript trigger

The usual way to go about this is:
define a route with cy.intercept()
click the button
wait for the response with cy.wait() to the route from 1.
To show it in one example:
cy // 1.
.intercept('POST', '/change-ad')
.as('changeAd');
cy // 2.
.get('#save-button')
.click();
cy // 3.
.wait('#changeAd')
.its('response.statusCode')
.should('eq', 201);
Obviously you can check other things on the UI after the response has arrived, that is after 3.
For some specific cases where you want to check how the UI reacts to some backend data without actually setting up the backend data first, you can "fake" the response (and status code and what not) in cy.intercept(). This is called stubbing.

Related

Cypress Spying on Vue components

I'm trying to write an e2e test using Cypress on my Vue app. I want to test if request on form submit returns correct value.
I know i need to use cy.spy. I also know I neet to spy on fetch method but I have no idea which object to tie it to.
From documantation:
The object that has the method to be wrapped.
Which for me would be the component I'm trying to test? I'm not sure if I'm interpreting this argument correctly. Can anyone explain?
EDIT:
My guess is that I need to use methods? But if I try to import them into my test_spec.js I get Cannot find module...
To spy over a response, you can use the route command instead of spy.
https://docs.cypress.io/api/commands/route.html
it('Example Test', function () {
cy.visit('https://stackoverflow.com/');
cy.server(); // cy.server needs to be invoked first in order to use cy.route command
cy.route({
url: `**/your/request/path/**`,
method: 'POST',
onResponse: (xhr) => {
console.log(xhr);
// here you can assert on xhr.response.body values
}
});
});

How do we call a function within the html file of vuejs defined in the javascript file of vuejs without creating a button in the html file?

I pretty new to vuejs and am building a vuejs project. One of the tasks I am stuck at is, that I want to call a function written in the javascript part of vuejs from the html part of vuejs without creating any buttons or textboxes. I want to call this function as soon as my app starts. How do I achieve this? When I use mounted (vue lifecycle hook), the page it redirects to keeps refreshing. would appreciate some leads on this.
For example, I have a code:
<template>
<h1>Hello World!</h1>
<!--I WANT TO CALL THE auth0login function here. How do I do that without creating a button/text field,etc -->
</template>
<script>
export default {
data: () => ({
return : {
clientID: process.env.example
}
}),
methods:{
auth0login(){
console.log('logging in via Auth0!');
Store.dispatch('login');
}
}
}
</script>
I want to call the auth0login function defined in the script part in the html part above in order to execute the functionalities of the auth0login function. I want to do this without creating any buttons in the html file and simply just execute the auth0login function when the app launches.
How do I do this?
You need to call auth0login() only when you're not already logged I guess.
I think the reason is after user already logged in, they go back to the initial page, and the function in mounted() hook run again. Thats why they keep get redirect to login page. This not happen when you insert the button, because the button require user to click at it.
To fix this, you need to define a vuex state to store whether user has logged in or not, and in mounted() hook, just called it when they not login yet.
So. Instead of
mounted: function() { console.log('logging in via Auth0!'); this.auth0login() } }
Add a check login state
mounted() {
if(!this.$store.state.userLoggin) // here i define userLoggin and vuex state, you should update it to true whenever user successfully login
{ console.log('logging in via Auth0!'); this.auth0login() //only call it when user not loggin
}
}
And remember to update your vuex state.userLoggin when user successfully login in the auth0login() function

Recommended way of waiting on an Apollo query before rendering the next page?

When using the Apollo module in a Nuxt app, the default behavior when changing routes is to render the new page immediately, before data has been fetched via Apollo.
This results in some pretty janky rendering experiences where the page does a partial render and very soon after completes rendering with data from the server, making everything on the page shift due to the changing size of components that now have data. This looks pretty bad because the data actually comes back fairly quickly, so it would be fine to wait for the data to return before rendering the new route.
What's the recommended way of waiting on the Apollo queries on a page (and its subcomponents) to complete before rendering the page?
(There's a related question that's not specific to Nuxt, but I'm not sure how to translate the recommendation to a Nuxt app.)
I'd love to see a code example of using beforeRouteEnter to fetch data via Apollo and only entering the route once the data is fetched.
Haven't used this module before, but it should be like any other async action you want to perform before page rendering in Nuxt.
It only depends if you want to pre-fill the store:
https://github.com/nuxt-community/apollo-module#nuxtserverinit
https://nuxtjs.org/guide/vuex-store/#the-nuxtserverinit-action
or only one page:
https://github.com/nuxt-community/apollo-module#asyncdatafetch-method-of-page-component
https://nuxtjs.org/guide/async-data
You can use async/await or promises if you have more than one request before page should be rendered.
When async actions are finished, Nuxt starts rendering the page. This works for SSR and if you navigate to pages on the client (nuxtServerInit will only fire once when real request is made, not when navigating on client side).
Side note: beforeRouteEnter is usually used, to validate params and check if the route is allowed.
did you try disabling the prefetch?
prefetch: false
The best approach is to use the loading attribute:
<template>
<div v-if="!this.$apollo.loading">
Your product: {{product}}
</div>
</template>
<script>
export default {
name: "Product",
apollo: {
product: {
query: productQuery,
variables() {
return {
productId: this.productId
}
}
}
}
}
</script>
I'm unfamiliar with Apollo, but I think this is what you are looking for:
// Router.js
beforeRouteEnter(to, from, next)
{
executeSomeApolloPromise().then((data) => {
// The promise has now been complete; continue to the component.
next((vm) => {
// You have access here to the component instance via `vm`.
// Note that `beforeRouteEnter` is the only guard that has this.
vm.someApolloData = data;
});
});
}
See https://router.vuejs.org/guide/advanced/navigation-guards.html#per-route-guard

Is it possible for Nuxt middleware to wait for asyncData requests to resolve?

I have a some middleware in my Nuxt app that closes a fullscreen mobile menu when a new route is clicked. What I am experiencing is the following:
user clicks nuxt-link
menu closes
asyncData delay (still shows current page)
new page is loaded upon resolved asyncData
What I would like is the following:
user clicks nuxt-link
asyncData delay (if exists)
menu closes upon new page load
Is it possible to have an asyncData watcher in Nuxt middleware?
I know I can hack this by creating a store value that tracks asyncData load, but I'd rather not have to wire up such a messy solution to each and every page that uses asyncData.
Note - not every page uses asyncData.
I think that the best option would be to leave the menu open, and then when the new page finishes loading (probably on the mounted hook) send an event or action to close the menu.
I figured this out in a more elegant solution than having to implement a store.dispatch function on each individual asyncData function.
So what I did was use a custom loading component: https://nuxtjs.org/api/configuration-loading/#using-a-custom-loading-component
However, instead of showing a progress bar or any sort of loading animation, I just used this component to set a loading state in my vuex store. Note - it forces you to have a template, but I just permanently disabled it.
<template>
<div v-if="false"></div>
</template>
<script>
export default {
methods: {
start() {
this.$store.dispatch('updateLoadingStatus', true);
},
finish() {
this.$store.dispatch('updateLoadingStatus', false);
}
}
};
</script>
Then in my middleware, I set up an interval watcher to check when loading has stopped. When stopped, I stop the interval and close the mobile menu.
export default function({ store }) {
if (store.state.page.mobileNav) {
if (store.state.page.loading) {
var watcher = setInterval(() => {
if (!store.state.page.loading) {
store.dispatch('updateMobileNav', false);
clearInterval(watcher);
}
}, 100);
} else {
store.dispatch('updateMobileNav', false);
}
}
}
This doesn't specifically have to be for a mobile menu open/close. It can be used for anything in middleware that needs to wait for asyncData to resolve. Hope this can help anyone in the future!

Is it possible to trigger programmatically a ember mirage request response

I use Ember mirage in my tests. I need to check the state of my tested component after a request has been send but before the respond has been received.
How it is possible to configure my test to avoid the mirage server responds automatically and trigger the response programmatically?
I used to do that with sinonjs but I do not find the way to manage this use case with Ember mirage. It is possible?
http://www.ember-cli-mirage.com/docs/v0.3.x/route-handlers/
You can add a handler like this inside your test:
server.get('/users/:id', function(db, request) {
console.log(request) // to debug request/response
return db.users.find(request.params.id);
});
If I understand your question correctly, you are trying to test a situation on the page (acceptance test) when data were sent to the server but the response still did not arrive.
It is possible to access server instance in your test, so it is not that complicated to create your own method that will pause/resume responding but the simpler option (that I use as well) is just to postpone response from mirage using timing option (http://www.ember-cli-mirage.com/docs/v0.3.x/configuration/#timing). Then, when you do your tests before andThen() you should be in a situation that you wish to test.
you can access the underlying pretender instance and the fact that mirage just passes the timing parameter straight through to the pretender request.
https://github.com/pretenderjs/pretender#timing-parameter
Unfortunately pretender doesn't have docs for requestReferences and requiresManualResolution(verb, path), but this helper function will process all outstanding manual requests
function resolveManualPretenderRequests(pretender) {
pretender.requestReferences.forEach((ref) => {
if (pretender.requiresManualResolution(ref.request.method, ref.request.url)) {
pretender.resolve(ref.request);
}
});
}
Then you can just use mirage to register a manual request handler
server.get('/models:id', { timing: true });
so in an example test, you can use the ember test helper waitFor() to do something like
test('button is disabled while loading', async function(assert) {
assert.expect(2);
// passing true to timing tells the underlying pretender handler wait for the request to be manually processed
server.get('/models/:id', { timing: true });
// await render will wait for promises to settle, but we actually don't want that
const renderPromise = render(hbs`<MyComponent />`);
// the waitFor() helper instead will allow us to just wait for our button to render
await waitFor('button');
const button = this.element.querySelector('button');
// since the request has not resolved yet, the button is disabled
assert.strictEqual(button.disabled, true);
// then we manually resolve the request
resolveManualPretenderRequests(server.pretender);
// now we can await the render so that we get our updated button state
await renderPromise;
// with the request resolved, now the button is no longer disabled
assert.strictEqual(button.disabled, false);
});