Click() is not working though there's no any error but element not opening up - (Cypress automation) - testing

last one cy.get('[data-cy=impact-area-table]').contains(impactareas.name).should('be.visible').click({force: true}); is not working though there's no any error ,it shows that it's fine and test pass but it doesnot open up the impact area ??
import { fillImpactAreaForm } from './utils';
import {contact, campaign, impactArea,impactareas} from '../support/commands.js';
describe('Fundraising test suite', function () {
beforeEach(() => {
cy.resetDb();
cy.visit('/');
});
it('should allow the user to create transactions', () => {
cy.seedOrgAndLogin().then(() => {
return cy.factoryCreate('PersonContacts', contact);
}).then(() => {
cy.factoryCreate('Campaigns', campaign);
}).then(() => {
cy.factoryCreate('ImpactAreas', impactArea);
}).then(() => {
cy.get('[data-cy="sidebar-Impact Areas"]').click({force: true});
cy.reload(true);
cy.get('[data-cy=create-impactarea]').click();
cy.get('[data-cy=impact-area-form]').contains('Close').click();
cy.get('[data-cy=create-impactarea]').click();
fillImpactAreaForm(impactareas);
cy. wait(2000);
cy.get('[data-cy=impact-area-table]').contains(impactareas.name).should('be.visible').click({force: true});
//cy.get('.content-scroll-wrapper.block-content').find('.content-scroll-body').contains(impactArea.name).click({force: true});
});
});
});

It's happening in 2 situations:
you don't have that item in your page or the dictation is different. (mention that cypress is case sensitive for .containt) or maybe your item is not visible.
you have more than one of this item. for example, you have 2 close in your page. it makes ambition to click on witch one. try to make it clear by adding more detail.

Related

Not able to store cookies in all the cypress tests

I am trying to automate my application with cypress. Have written few tests in my class and before visiting the site I have set up cookies (To login without entering username, password and otp). I have tried several ways to store these cookies and call before each of these tests but cookies work only for the 1st test and I am logged out for the subsequent tests.
Please find my code below. I am calling data using fixtures. It works fine only when i set sso and user agent for every test and I want to eliminate this.
describe('Watchlist Testsuite', () => {
let data;
before(() => {
cy.fixture('example').then((fdata) => {
data = fdata;
});
});
it('Setting up cookies', () => {
cy.setupCookies(data.sso, data.uid, data.userAgent, data.devId, data.url)
.then(() => cy.visit(data.url))
})
it('Enter Passcode', () => {
cy.setCookie('x-sso-token', data.sso)
cy.setCookie('x-user-agent', data.userAgent)
Cypress.config('pageLoadTimeout', 2000)
cy.enterPasscode(data.passcode)
Cypress.config('pageLoadTimeout', 20000)
cy.closeOKButton()
})
it('Create a watchlist', () => {
cy.setCookie('x-sso-token', data.sso)
cy.setCookie('x-user-agent', data.userAgent)
watchlistTest.createWatchlist(data.watchlistName)
})
Below are the ways with which I tried to preserve the cookies for all tests but none of them seem to be working.
Setting up cookies in beforeeach method
beforeEach('Setup cookies', ()=> {
cy.setupCookies(data.sso, data.uid, data.userAgent, data.devId, data.url)
.then(() => cy.visit(data.url))
})
Using cookies defaults
Cypress.Cookies.defaults
({
preserve:[data.sso, data.userAgent]
})
Using cy.session (I have set experimentalSessionAndOrigin to true)
it('setting up cookies',() => {
console.log('sso is ', data.sso)
const validate = () => {
cy.getCookie(data.sso).should('exist')
}
cy.session([window.sessionStorage.setItem('x-sso-token', data.sso),
window.sessionStorage.setItem('x-uid', data.uid),
window.sessionStorage.setItem('x-user-agent', data.userAgent),
window.sessionStorage.setItem('dev-id', data.devId)], {validate})
})
PS: I am using the Cypress 10.3.1 version.
Please guide me on the right approach to solve the issue.

LayoutAnimation not working when reordering flatlist items

I'm trying to let my flatlist animate every time the order of my list gets changed. For this I tried using the LayoutAnimation API from react native. My state gets updated via redux. When I delete or add new items to the list it works completely fine but it doesn't when I try to change the sortOrder in all my items.
Code
When I finishing a workout. I log the workout which returns me the new reordered workoutList from my API.
LayoutAnimation.easeInEaseOut();
dispatch(logWorkout(inputWorkout));
navigation.navigate("WorkoutListScreen");
logWorkout
export const logWorkout = (workout: Workout) => async (
dispatch: Dispatch<WorkoutDispatchTypes>
) => {
console.log('WORKOUT_LOG_ACTION');
// dispatch({
// type: LOG_WORKOUT_LOADING,
// })
_logWorkout(workout)
.then((result: any) => {
handleNewTokenForRequest(result.headers.authorization, dispatch);
// LayoutAnimation.easeInEaseOut()
dispatch({
type: LOG_WORKOUT_SUCCESS,
payload: {
workoutList: result.data.filter(
(item: any) => item.archived === false
),
archivedWorkoutList: result.data.filter(
(item: any) => item.archived === true
),
message: lang.t('LOG_WORKOUT_SUCCESS'),
},
});
dispatch < any > getLogHistory();
})
.catch((err) => {
if (handleUnauthorizedRequest(err, dispatch)) return;
console.log(err.response);
console.log(err);
dispatch({
type: LOG_WORKOUT_FAIL,
payload: {
message: lang.t('LOG_WORKOUT_FAIL'),
},
});
});
};
Attempts
I got the sortOrder of every item as the item´s key.
KeyExtractor of the Flatlist is also using the sortOrder of the items.
My LayoutAnimation is executed before my state is updated.
I have also tried to use Transitions from react reanimated
Also added the following code to make it work for android
if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
I don't really know what else to try.
Please let me know if you need some code or further information.
Does anybody have a tip for me? I really don't understand why it's not working.
Nobody got an idea? I still couldn't fix the problem.

How to share response data across multiple suites?

Let's say we have the following suite:
describe('Devices', () => {
describe('Master Data Set-Up', () => {
it('should create the device if necessary', () => {
cy.createDevice()
its('body.id')
.as('deviceId');
});
});
describe('Test Suite 1', () => {
it('should allow to send data to device', () => {
cy.get('#deviceId').then((deviceId) => {
cy.sendData(deviceId, 'Some Data');
});
});
});
});
So, we have a set up suite that creates master data. This is a simplified version, actually it contains a couple of it specs and I'd like to keep it like that because it's better to read in the Cypress output.
Then, there is the actual test suite that want's to use data that has previously been created. In this case a server generated id that should be used for another REST call.
This is assuming, that cy.createDevice and cy.sendData are custom commands available that internally use cy.request.
When running that, cy.get('#deviceId') fails because aliases are not shared across describe blocks AFAIK. I tried to use let deviceId but it's undefined as it is not yet available when the test specs are processed.
What is a proper way to do this?
I believe this will be better solution, as cypress is asynchronous so it's better to write it on file and read it
describe('Devices', () => {
describe('Master Data Set-Up', () => {
it('should create the device if necessary', () => {
cy.createDevice()
......
cy.writeFile('deviceId.txt', body.id)
});
});
describe('Test Suite 1', () => {
it('should allow to send data to device', () => {
cy.readFile('deviceId.txt').then((device_id) => {
cy.sendData(device_id, 'Some Data');
})
});
});
});
Upvote for #ArekKhatry's idea, but to be safe I would obtain the the id in a before(). If you ever run tests in parallel, grabbing data from one test to use in another would be flaky.
Note that running cy.createDevice().its('body.id') in the before() still gives you the same test coverage as running inside it(), i.e it tests that the request succeeds and the return value has an id.
The file should be written to cypress/fixtures, otherwise it will write to the project root causing untidy pollution of the file structure.
Also, the id is returned from cy.request() as a number, but must be stringifyed in order to write to a text file.
Here's my variant
describe('Devices', () => {
before(() => {
cy.createDevice()
.its('body.id')
.then(id => {
cy.writeFile('cypress/fixtures/deviceId.txt', id.toString());
cy.log(`Created device: ${id}`);
});
});
describe('Test Suite 1', () => {
it('should allow to send data to device', () => {
cy.fixture('deviceId') // can use simpler cy.fixture here
.then(device_id => { // returned as a string here
const id = parseInt(device_id); // may need to parse to number?
cy.sendData(id, 'Some Data');
})
});
});
});
Ok, so first thanks to Aloysius and Arek for their answers. But I had the gut feeling that there must be some easier way to do this that writing an Id to a file.
As I mentioned before, I had issues with my first attempt to use a global variable:
I tried to use let deviceId but it's undefined as it is not yet
available when the test specs are processed.
I really wanted to understand, why this did not work and did some console debugging.
I added a console log:
describe('Devices', () => {
console.log('Loading test suites...')
(...)
});
When running the tests, I saw the log output twice, once after the first describe block where the device id was stored and then a second time after the master data was written.
Actually, I found out that this issue was cause by the following known Cypress issue:
https://github.com/cypress-io/cypress/issues/2777
After setting the baseUrl, it actually works:
describe('Devices', () => {
let deviceId;
before( () => {
Cypress.config('baseUrl', Cypress.env('system_url'))
cy.visit('/');
})
describe('Master Data Set-Up', () => {
it('should create the device if necessary', () => {
cy.createDevice()
.its('body.id')
.then((id) => {
deviceId = id;
});
});
});
describe('Test Suite 1', () => {
it('should allow to send data to device', () => {
cy.sendData(deviceId, 'Some Data');
});
});
});

Are Loops Possible in Detox testing

Is it possible to loop through items in Detox? For example if you have many testid’s of the same type that simply increment by 1 in name, can it be looped in way that wouldn’t require the statements to be fully typed out each time?
Yes, its possible. Here you can see the code of a test that:
loads first screen
loops through a small list of items
taps nth item
navigates to second screen
grabs a screenshot
Hope it helps
const { takeScreenshot } = require ('./helpers')
describe('Example', () => {
let artistList, artistListItem
let tagsList
beforeEach(async () => {
await device.reloadReactNative();
})
afterEach(async () => {
takeScreenshot() //https://medium.com/async-la/e2e-testing-react-native-with-detox-screenshots-595146073863
})
var fnTest=(i)=>{
it('should navigate to '+i+'nth artist', async () => {
await expect(element(by.id('artistList'))).toBeVisible()
await element(by.id('artistListItem'+i)).tap()
})
}
for (var i=0; i<3; i++){
fnTest(i)
}
})

Pusher Chatkit in Vue - onNewMessage hook triggered twice?

I have a Vue.js application using the Pusher Chatkit.
I have a problem I haven't been able to find an answer for some time now.
Whenever I re-visit a view/component the Chatkit onNewMessage() hook is triggered multiple times. It depends on the times I re-visit the page.
Page refresh or first-time load resolves the issue until next re-visit.
It must be that I am creating multiple listeners each time I visit the view, but I don't get what these listeners are.
Pusher states that room subscriptions "override" the old ones when done twice.
Here is my chat.vue component
import chatConnection from '../chatkit.js'
created(){
let chatManagerConnectPromise = chatConnection(this, uid)
Promise.all([..., chatManagerConnectPromise, ...])
.then(results => {
// ...
this.initiateNewChatState(results[1])
// ...
})
.catch(error =>{
});
},
methods: {
initiateNewChatState(currentUser){
this.subscribeToAllUserRooms(currentUser)
},
subscribeToAllUserRooms(currentUser){
for(let room of currentUser.rooms){
this.subscribeToRoom(currentUser, room.id)
}
},
subscribeToRoom(currentUser, roomId){
currentUser.subscribeToRoom({
roomId: roomId,
hooks: {
onNewMessage: message => {
console.log("CHAT | onNewMessage | new: ", message.text)
}
},
messageLimit: 10
})
.catch(error => {
this.notifyError("Uh oh", "Something is not right")
});
}
}
And here is my chatkit.js content:
import { ChatManager, TokenProvider } from '#pusher/chatkit'
export const chatConnection = ({ state, actions }, uid) =>{
return new ChatManager({
instanceLocator: "##:###:###:####:####",
userId: uid,
tokenProvider: new TokenProvider({url: 'https://...' })
})
.connect({
onAddedToRoom: room => {
// some action taken
},
onRemovedFromRoom: room => {
// some action taken
},
onRoomDeleted: room => {
// some action taken
}
})
.then(user => {
return user
})
.catch(error => console.log('CHATKIT | Error on connection', error))
}
Again, the problem is that the onNewMessage() is triggered once the first time after the page refresh/first load, but then increases by one with each new page visit (back and forth navigation).
I am creating some listeners with each visit but it cannot be the ChatManager not the User.subscribeToRoom!?
Thanks for any pointers.