I have tried many but have not been successful, please help me with the example. I have put all code here you can also try it on your system.
I am testing registration flow using cypress. and I don't want to clear cache/cookies before each test. can anyone help me?
This is my test file, and the first describe block is to send OTP for entered email. the second one is to create a temporary email and save OTP into a JSON file for letter use. and the third one is for verifying OTP using API. but when I use the same URL and enter an email which OTP verified by API it shows 500 Internal server error
const faker = require("faker");
const firstName = faker.Name.firstName();
const lastName = faker.Name.lastName();
const email = firstName + "#mailinator.com";
describe('My Test Suite', function () {
it('Otp Test', function () {
cy.visit('https://outsized.site/')
cy.get('.css-jqdzg6-commonButtonStyle > canvas', { timeout: 30000 }).click()
cy.get('#email').type(email.toLocaleLowerCase())
cy.get('.ant-btn').click()
cy.fixture('data1').then((profile) => {
profile.FreelancerName = firstName.toLocaleLowerCase()
profile.FreelancerEmail = email.toLocaleLowerCase()
cy.writeFile("cypress/fixtures/data1.json", profile)
cy.wait(2000)
})
})
})
context('My Test Suite', function () {
it('Otp Test', function () {
cy.visit('https://www.mailinator.com/')
cy.fixture("data1.json").then(profile => {
cy.get("#addOverlay").type(profile.FreelancerName)
})
cy.get("#go-to-public").click()
cy.wait(2000)
cy.contains('table tbody tr', 'OTP').click() // find the right email
cy.get('#html_msg_body') // iframe
.its('0.contentDocument.body').should('not.be.empty') // wait for loading
.then(console.log) // works with this but errors without - totally weird
.wait(0)
.find("table > tbody > tr:nth-child(3) > td > h2")
.then($h2 => {
const OTP = $h2.text()
cy.fixture("data1.json").then(profile => {
profile.OTP = OTP
cy.writeFile("cypress/fixtures/data1.json", profile);
})
})
})
})
context('My Test Suite', function () {
it('Otp Test', function () {
cy.fixture('data1').then((profile) => {
cy.request({
method: 'POST',
url: 'https://api.outsized.site/graphql',
headers: {
'Content-Type': 'text/plain'
},
body:
'mutation { verifyEmailOtp(email: "' + profile.FreelancerName + '#mailinator.com", otp: ' + profile.OTP + '){ message } }'
})
})
cy.wait(5000)
cy.fixture("data1.json").then(profile => {
cy.visit("https://outsized.site")
cy.wait(5000)
//cy.visit(profile.url+profile.FreelancerName+"%40"+"mailinator.com")
cy.get('.css-jqdzg6-commonButtonStyle > canvas', { timeout: 30000 }).click()
cy.get('#email').type(profile.FreelancerEmail)
cy.get('.ant-btn').click()
cy.request({
method: 'POST',
url: 'https://api.outsized.site/graphql',
headers: {
'Content-Type': 'text/plain'
},
body:
'mutation { addNewEmail(email: "' + profile.FreelancerName + '#mailinator.com"){ message } }'
})
cy.get('.ant-btn').click()
})
})
})
500 Internal server error get because cypress has clear cache and cookies before each test.
There's a relatively new command cy.session() (docs) that preserves cookies, localStorage, and sessionStorage. Not sure if that includes "cache", in fact I don't know what you refer to there.
The way it works is you can add it into a beforeEach() so it gets called by each test, but it only calls the code inside once (first test), then for subsequent calls it retains and restores the values from the above stores that were set during the first test.
There's an example here Unable to access modal-dialogue in cypress which is simpler than the examples in the official documents.
The basic pattern is worth repeating
Cypress.config('experimentalSessionSupport', true) // set this flag
beforeEach(() => {
cy.session('mySession', () => {
// code that sets cookies, only called once
// thereafter same cookies, localstorage, sessionStorage
// are preserved for future test
})
})
I can't really tell what code you need from your sample above, but I'm sure you know already.
Related
I am new to Cypress trying to run an e2e test. My modest goal is to create an account and login with that account. My expected result is that I get some indication that the line I highlight with a comment // should fail! reports a failure. My actual result is that I don't get much of anything!
Error message: none! kind of.
I get some messages about failed post requests, does this matter? See the red "POST 400". Does that interrupt my tests?
Here's my test:
it("registers, logs in, and waits for the refresh token to refresh", async () => {
cy.visit(baseFrontendUrl);
const loginResponse = await axios.post(baseBackendUrl + "/auth/email/login", { email: "rm" });
const accessToken = loginResponse.data.accessToken;
console.log(accessToken, "access token");
const allUsersResponse = await axios.get(baseBackendUrl + "/auth/all", {
headers: { Authorization: "Bearer " + accessToken },
});
const allUsers: Member[] = allUsersResponse.data;
console.log(allUsers, "24rm");
const allTestAccounts = allUsers.map((m: Member) => m.googleId.slice(0, 4) === "TEST");
const nextTestAccountFieldValue = "TEST" + (allTestAccounts.length + 1).toString();
const nextTestAccount = {
email: nextTestAccountFieldValue,
firstName: nextTestAccountFieldValue,
lastName: nextTestAccountFieldValue,
fakeGoogleId: nextTestAccountFieldValue,
};
cy.get("#devPortal").should("have.text", "SHOULD OBVIOUSLY FAIL"); // doesn't fail!
cy.get("#signUpEmail").type(nextTestAccount.email);
cy.get("#signUpFirstName").type(nextTestAccount.firstName);
cy.get("#signUpLastName").type(nextTestAccount.lastName);
cy.get("#signUpGoogleId").type(nextTestAccount.fakeGoogleId);
cy.get("#signUpButton").click();
// assert
cy.get("#msg").should("have.text", "Successful registration").should("be.visible"); // doesn't seem to run at all
}
Neither of the requests in the above code fail; they work fine and I know that because the accessToken value logs something.
Putting expect(true).to.equal(false) does show assertexpected true to equal **false** AssertionError and "true to be true" does give assertexpected true to equal **true** so perhaps I don't understand should?
And in case its not clear, the text for #devPortal# is not "should obviously fail"! :-) Sign up with email: `
I don't know what to look for because I am newb at Cypress. It's something obvious, I'm sure.
edit: So I disabled the bunch of axios requests at the top. The tests worked after that:
edit2: This solution isn't perfect because I want to (a) get the list of users => (b) get the # of test accounts => (c) increment the # at the end of "testAccount" by 1 so the e2e test runs with a new account. I need to login, get an access token, and hit an endpoint, for this to work. Hence the question becomes, "why does running an axios request at the start of the test make it malfunction?"
The axios calls are succeeding, but they aren't part of the test they just set up some "fixture" data for the sign-in test itself.
I would separate that block of code out to make things more understandable.
Usually you will make API calls using cy.request() rather than axios, and
then you don't need async/await which are in fact "illegal" in Cypress (the commands don't return promises so you can't await them).
beforeEach(() => {
cy.request('POST', baseBackendUrl + "/auth/email/login", { email: "rm" })
.then(response => {
const accessToken = response.data.accessToken;
cy.request(baseBackendUrl + "/auth/all", {
headers: { Authorization: "Bearer " + accessToken },
})
.then(response => {
const allUsers: Member[] = response.data;
const allTestAccounts = allUsers.map((m: Member) => m.googleId.slice(0, 4) === "TEST");
const nextTestAccountFieldValue = "TEST" + (allTestAccounts.length + 1).toString();
const nextTestAccount = {
email: nextTestAccountFieldValue,
firstName: nextTestAccountFieldValue,
lastName: nextTestAccountFieldValue,
fakeGoogleId: nextTestAccountFieldValue,
};
cy.wrap(nextTestAccount).as('nextAccount') // use alias to save value
})
})
})
})
// no need for async when using cy.request()
it("registers, logs in, and waits for the refresh token to refresh", () => {
cy.get('#nextAccount').then(nextTestAccount => {
cy.visit(baseFrontendUrl);
...
I think your problem with the .should() not failing the test may be due to the async/await around the test. Obviously the assert is failing as it's logging red, but if the test is still passing then it looks like a timing issue - the test is completing too soon.
I have a function which returns a middleware as such:
const jsonParser = () => {
return express.json({
limit: '5mb',
verify: (req, res, buf) => {
// If the incoming request is a stripe event,
if (req.headers['some-header']) {
httpContext.set('raw-body', buf.toString());
}
},
});
};
I would like to test that the httpContext.setis indeed called when the some-header header is present.
My test:
describe('jsonParser middleware', () => {
it('sets the http context', async () => {
const req = {
headers: {
'some-header': 'some-sig',
'content-type': 'application/json',
},
body: JSON.stringify({
some: 'thing',
}),
};
const res = {};
const middleware = jsonParser();
middleware(req, res, () => {});
expect(httpContext.set).toHaveBeenCalled();
});
});
I have no idea how to make the test run the function passed to verify. Express docs state that the content type should be json, but nothing more. Anyone that can point me in the right direction is highly appreciated.
Thank you.
as mentioned in the comments i want to give you an example of an integration test which tests the header and jsonwebtoken. i am also using the express framework but i wrote my code in JS.
this is a test for creating a forumpost in a forum i built. a middleware is checking for the token of the user so this case could be similiar to yours.
const request = require('supertest');
test('create authorized 201', async () => {
const forumCountBefore = await ForumPost.countDocuments();
const response = await request(app)
.post('/api/forumPosts')
.set({
Authorization: `Bearer ${forumUserOne.tokens[0].token}`,
userData: {
userId: forumUserOneId,
email: 'forum#controller.com',
username: 'forum',
},
})
.send(forumPost)
.expect(201);
expect(response.body.message).toBe('created forumPost');
const forumCountAfter = await ForumPost.countDocuments();
expect(forumCountBefore + 1).toBe(forumCountAfter);
});
i am using mongoDB thats why i use ForumPost.countDocuments to count the amount of entries in the DB.
as you can see in the test i use supertest (imported as request) to send an http call. in the set block i set the authorization token. this causes the middleware to be executed in the integration test.
the test can only pass when the code of the middleware gets executed correctly so it should cover the code of your middleware.
The steps I want to take are:
Start the Cypress test-suite and use cy.setCookie to set the JSESSIONID cookie (already acquired and up-to-date)
After the cookie is set, then use cy.visit to access the running app
The issue:
The cookie is not set before cy.visit runs and this causes the app redirect to an unauthorized page
What I have done so far:
Cypress.Cookies.defaults({
preserve: 'JSESSIONID'
})
cy.setCookie('JSESSIONID', Cypress.env('JSESSIONID'), {
path: '/',
domain: '<domain.name>',
httpOnly: true,
secure: true,
sameSite: 'no_restriction',
log: true,
}).then(() => cy.visit('localhost:3000/<authenticated-route>')
It might be worth mentioning that <domain.name> is of the form www.staging.etc.com whereas is running locally: localhost:3000/
Any help would be greatly appreciated. Thanks in advance
I solved the issue by doing a cy.request to login before using cy.visit.
Code looks something like this:
const login = () => {
const headers = new Headers()
headers.append("Content", "application/x-www-form-urlencoded")
headers.append("Accept-Encoding", "gzip:deflate")
headers.append("Content-Type", "application/x-www-form-urlencoded")
cy.request({
url: Cypress.env("LOGIN_URL"),
method: 'POST',
form: true,
headers,
body: {
"email": Cypress.env("EMAIL"),
"password": Cypress.env("PASSWORD")
}
}).then((response) => {
console.log(response)
console.log(response.body)
setCookie(response.COOKIE)
})
}
export const loginAndStartTests = () => {
login()
cy.visit('/<homepage>')
}
Take a look at Provide an onBeforeLoad callback function
The example recipe mentioned (code is here) is setting a token in local storage, but should apply as well to cookies
cy.visit('http://localhost:3000/#dashboard', {
onBeforeLoad: (contentWindow) => {
cy.setCookie('JSESSIONID', Cypress.env('JSESSIONID'), {
path: '/',
...
})
}
})
I think the problem is that cy.visit() is one of the places where everything is cleared down, but the hook is provided to get around that. Although, I would expect preserve to work as well.
You need to set a cookie from the argument contentWindow:
A cookie setter util:
export const setCookieToContentWindow = (
contentWindow,
name,
value,
{ expireMinutes = 1 } = {},
) => {
const date = new Date();
const expireTime = expireMinutes * 60 * 1000;
date.setTime(date.getTime() + expireTime);
const assignment = `${name}=${encodeURIComponent(value)}`;
const expires = `expires=${date.toGMTString()}`;
const path = 'path=/';
contentWindow.document.cookie = [assignment, expires, path].join(';');
};
Using onBeforeLoad:
cy.visit('http://localhost:3000/#dashboard', {
onBeforeLoad: (contentWindow) => {
setCookieToContentWindow(contentWindow, 'COOKIE_NAME', 'COOKIE_VALUE');
},
});
I'm developing a Vue.js application which has only frontend (no server) and send a lot of requests to different APIs. The originally quite simple app became more complex. And there are problems with some APIs, because browsers do not accept the responses due to CORS. That is why I'm trying to test, if I can migrate the app to Nuxt.js.
My approach is as follows (inspired by this comment), but I expect, that there is probably a better way to send the requests from the client over the server.
pages/test-page.vue
methods: {
async sendRequest(testData) {
const response = await axios.post('api', testData)
// Here can I use the response on the page.
}
}
nuxt.config.js
serverMiddleware: [
{ path: '/api', handler: '~/server-middleware/postRequestHandler.js' }
],
server-middleware/postRequestHandler.js
import axios from 'axios'
const configs = require('../store/config.js')
module.exports = function(req, res, next) {
let body = ''
req.on('data', (data) => {
body += data
})
req.on('end', async () => {
if (req.hasOwnProperty('originalUrl') && req.originalUrl === '/api') {
const parsedBody = JSON.parse(body)
// Send the request from the server.
const response = await axios.post(
configs.state().testUrl,
body
)
req.body = response
}
next()
})
}
middleware/test.js (see: API: The Context)
export default function(context) {
// Universal keys
const { store } = context
// Server-side
if (process.server) {
const { req } = context
store.body = req.body
}
}
pages/api.vue
<template>
{{ body }}
</template>
<script>
export default {
middleware: 'test',
computed: {
body() {
return this.$store.body
}
}
}
</script>
When the user makes an action on the page "test", which will initiate the method "sendRequest()", then the request "axios.post('api', testData)" will result in a response, which contains the HTML code of the page "api". I can then extract the JSON "body" from the HTML.
I find the final step as suboptimal, but I have no idea, how can I send just the JSON and not the whole page. But I suppose, that there must be a much better way to get the data to the client.
There are two possible solutions:
Proxy (see: https://nuxtjs.org/faq/http-proxy)
API (see: https://medium.com/#johnryancottam/running-nuxt-in-parallel-with-express-ffbd1feef83c)
Ad 1. Proxy
The configuration of the proxy can look like this:
nuxt.config.js
module.exports = {
...
modules: [
'#nuxtjs/axios',
'#nuxtjs/proxy'
],
proxy: {
'/proxy/packagist-search/': {
target: 'https://packagist.org',
pathRewrite: {
'^/proxy/packagist-search/': '/search.json?q='
},
changeOrigin: true
}
},
...
}
The request over proxy can look like this:
axios
.get('/proxy/packagist-search/' + this.search.phpLibrary.searchPhrase)
.then((response) => {
console.log(
'Could get the values packagist.org',
response.data
)
}
})
.catch((e) => {
console.log(
'Could not get the values from packagist.org',
e
)
})
Ad 2. API
Select Express as the project’s server-side framework, when creating the new Nuxt.js app.
server/index.js
...
app.post('/api/confluence', confluence.send)
app.use(nuxt.render)
...
server/confluence.js (simplified)
const axios = require('axios')
const config = require('../nuxt.config.js')
exports.send = function(req, res) {
let body = ''
let page = {}
req.on('data', (data) => {
body += data
})
req.on('end', async () => {
const parsedBody = JSON.parse(body)
try {
page = await axios.get(
config.api.confluence.url.api + ...,
config.api.confluence.auth
)
} catch (e) {
console.log('ERROR: ', e)
}
}
res.json({
page
})
}
The request over API can look like this:
this.$axios
.post('api/confluence', postData)
.then((response) => {
console.log('Wiki response: ', response.data)
})
.catch((e) => {
console.log('Could not update the wiki page. ', e)
})
Now with nuxtjs3 :
nuxtjs3 rc release
you have fetch or useFetch no need to import axios or other libs, what is great, automatic parsing of body, automatic detection of head
fetching data
you have middleware and server api on same application, you can add headers on queries, hide for example token etc
server layer
a quick example here in vue file i call server api :
const { status } = await $fetch.raw( '/api/newsletter', { method: "POST", body: this.form.email } )
.then( (response) => ({
status: response.status,
}) )
.catch( (error) => ({
status: error?.response?.status || 500,
}) );
it will call a method on my server, to init the server on root directory i created a folder name server then api, and a file name newsletter.ts (i use typescript)
then in this file :
export default defineEventHandler(async (event) => {
const {REST_API, MAILINGLIST_UNID, MAILINGLIST_TOKEN} = useRuntimeConfig();
const subscriber = await readBody(event);
console.log("url used for rest call" + REST_API);
console.log("token" + MAILINGLIST_TOKEN);
console.log("mailing list unid" + MAILINGLIST_UNID);
let recipientWebDTO = {
email: subscriber,
subscriptions: [{
"mailingListUnid": MAILINGLIST_UNID
}]
};
const {status} = await $fetch.raw(REST_API, {
method: "POST",
body: recipientWebDTO,
headers: {
Authorization: MAILINGLIST_TOKEN,
},
}).then((response) => ({
status: response.status,
}))
.catch((error) => ({
status: error?.response?.status || 500,
}));
event.res.statusCode = status;
return "";
})
What are the benefits ?
REST_API,MAILING_LIST_UNID, MAILING_LIST_TOKEN are not exposed on
client and even file newsletter.ts is not available on debug browser.
You can add log only on server side You event not expose api url to avoid some attacks
You don't have to create a new backend just to hide some criticals token or datas
then it is up to you to choose middleware route or server api. You don't have to import new libs, h3 is embedded via nitro with nuxtjs3 and fetch with vuejs3
for proxy you have also sendProxy offered by h3 : sendProxy H3
When you build in dev server and client build in same time(and nothing to implement or configure in config file), and with build to o, just don deploy your project in static way (but i think you can deploy front in static and server in node i don't know)
I'm facing an issue while using react native fetch api. many times request got failure . I have a high speed connection. but many times it got failed.
that issue is happening In android,ios both.
const shoppingApi = 'myserverlink';
async function Sendshoppinapi(data) {
try {
let response = await fetch(shoppingApi, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'multipart/form-data'
},
body: data
});
let responseJson = await response.json();
return responseJson;
}
catch (error) {
Alert.alert(error.toString())
}
}
export {Sendshoppinapi};
data that I sending server as post request
add_to_wishlist = (item,index) => {
{
let data = new FormData();
data.append('methodName', 'add_to_wishlist');
data.append('user_id', global.userid)
data.append('item_id', this.props.navigation.state.params.itemid.toString())
Sendshoppinapi(data).then((responseJson)=>{
console.warn(responseJson);
if(responseJson.responseCode == '200'){
this.setState({fav:false})
Alert.alert('SHOPPING','Item added to wishlist successfully.',[{text: 'OK',},],{ cancelable: false })
}
else{
this.setState({fav:false})
Alert.alert('SHOPPING','Item already .',[{text: 'OK',},],{ cancelable: false })
}
})}
}
Error that when request got failed
I've quoted an answer I used for another post - however I have added await.
You can check the status of the call, to determine perhaps why the network call failed. Try using fetch's ok to check whether the response was valid, for example:
.then(function(response) {
if (!response.ok) {
//throw error
} else {
//valid response
}
})
Using await:
let response = await fetch(url)
if (response.ok) return await response.json()
You can also access the response's status like:
response.status;
or also, statusText such as:
response.statusText;
checkout the below:
https://developer.mozilla.org/en-US/docs/Web/API/Response/statusText
https://developer.mozilla.org/en-US/docs/Web/API/Response/status
https://www.tjvantoll.com/2015/09/13/fetch-and-errors/
Use then() function with promises. (Requested code snippet)
fetch(shoppingApi, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'multipart/form-data'
},
body: data
})
.then((resp) => {
return resp.json()
})
.then((resp) => {
//resp contains your json data
});
You also can make your function returns a Promise, and use it with then():
function sendShoppingApi(data) {
return new Promise((resolve, reject) => {
fetch(shoppingApi, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'multipart/form-data'
},
body: data
})
.then((resp) => {
return resp.json();
})
.then((resp) => {
resolve(resp);
/*
you should also check if data is valid, if something went wrong
you can reject the promise:
if(!dataOK)
reject("error message");
*/
});
});
}
So now you can do something like this:
sendShoppingApi(data)
.then((resp) => {
//do stuff with your data
})
.catch((err) => {
//handle error
});
UPDATE
could be a duplicate of this: React Native fetch() Network Request Failed
For the case when you are running the app on the android device, the API is on a computer and both of them are on the same network I have added some possible things to check. I haven't detailed specific solutions since there are many answers on each topic.
Do a quick check with ngrok https://ngrok.com/ on the free plan to see if that works. If yes:
Make sure the API is accessible by trying to access it on the device browser (most important is to check if you allow the port at inbound rules, firewall).
If you are using HTTPS, you might get an error if your react native env is not properly configured to accept not trusted certificates, assuming you are using a non trusted one. Do a check without HTTPS, only with HTTP, to see if it's the case. https://github.com/facebook/react-native/issues/20488