Assertion is started before request in cypress - javascript

I have a problem that when i run below code
cy.contains("Lion").click();
cy.get('rows').each((row) => {
expect(row.text()).to.include("Lion");
});
The assertion above is run before the request that is done after: cy.contains("Lion").click(); is executed which will fail the application. The request is done using graphQL

So first there is no property rows in cy, but even if you added through support.js then cy functions return promises, check this for further info.
you have to use .then (here) to access the cypress values i.e your code will be something like this
cy.contains("Lion").click();
cy.get('rows').then($rows => $rows.each((row) => {
expect(row.text()).to.include("Lion");
}));

Related

mssql execute: return both promise and recordsets

I am using node-mssql to perform a bunch of operations inside a transaction. Spcifically, the methods used in order are begin tran,bulk,bulk,exec,commit. Here is part of the code, which works as-is:
// bulk insert #columns
.then(result => {
const request=new sql.Request(globalTx);
const tableObj = new sql.Table('#columns'); //#columns
/* some code to build the desired tableObj*/
return request.bulk(tableObj);
})
// exec proc
.then(result => {
returnObject.lastSuccessfulStep='bulk #data'
returnObject["#columns rows"]=result.rowsAffected
const request=new sql.Request(globalTx);
/* some code to build the desired proc call*/
return request.execute('spc_sqlDMLCommand');
})
//commit
.then(result => {
return globalTx.commit(); // returns promise
})
So you can see the use of chained .thens. There is a catch() at the end.
My problem is that in the case od the execute method, while the then() /catch() promise structure feels friendly to me, I also need the information that the method returns through its callback. Citing the reference about the second parameter:
callback(err, recordsets, returnValue) - A callback which is called
after execution has completed, or an error has occurred. returnValue
is also accessible as property of recordsets. Optional. If omitted,
returns Promise.
Is there a way to save err/recordsets/returnValue to some objects while still maintaining the flow, ie not having to cut-paste the subsequent then()s into the execute's callback?
Solution attempt:
I tried using a callback:
request.execute('spc_sqlDMLCommand',function cb(a,b,c){
console.log('a:\n',a,'b:\n',b,'c:\n',c)
});
but I got this error:
message: 'Requests can only be made in the LoggedIn state, not the
SentClientRequest state', code: 'EINVALIDSTATE'
Following this up on the internet, it seems to be about multiple queries having problems. But, it already works for me if I do it in the way mentioned above...

How to nest promises with truffle deployer in truffle migration script

I am using truffle deployer to deploy my solidity contracts:
module.exports = function(deployer, network) {
...
}
I would like to store some data on the chain within this migration process. Basic storing of data is working properly by using the promise callback parameter and call some functions on the contract. But I need to do something more complex like explained in the following code snippet:
deployer.deploy(A).then(instance => {
instance.addB(id, some params ...).then(result => {
// result is not the added B -> using getB() to load B
instance.getB(id).then(instanceB => {
instanceB.addC(id, some params ...);
})
});
})
The problem is, that the inner functions are not executed properly. instance.addB() does properly store B into the chain. But C is never stored to the chain and I don't get why.
Also if I add console.log('some text') to the inner function it's not printed to the console.
Does someone know how to resolve this issue?
Use "await/async" instead of the promise callbacks.

Method inside class is not getting executed in unit test

I have a class which contains methods.Now after initializing the class i want to invoke the methods but my test flow is not to the method and getting error like Uncaught error outside test suite.Below is my code
describe('Test Stu positive', () => {
it("Test Stu positive", (done) => {
const stuDetails = new masterDetails(getdetails);
expect(stuDetails.retrieveStudent(res => {
console.log(res);
done()
}))
});
});
Now, in the above code i am not able to print console.log(res);. What i am doing wrong?
I believe that you are using Mocha as your testing framework and looks like the error is not being handled by mocha, because is an asynchronous operation and you are not passing the error to the done callback method as described in the mocha documentation
it is really hard to tell how your function works, if it returns a promise or if it just uses a callback and the error is handled inside the function, so I can't provide you a code example on how to accomplish this. if you mind providing your function declaration I can update my answer with an example solution.

Promise.reject and wait for correct execution order when testing with Jest and Enzyme [duplicate]

This question already has answers here:
Testing with React's Jest and Enzyme when simulated clicks call a function that calls a promise
(2 answers)
Closed 4 years ago.
I am testing a component that uses an external Api.js file. When testing the component, I'm mocking the function using
import {
apiCall,
} from './Api';
jest.mock('./Api');
I want to test a case where the Api call fails, to check that my component shows the correct error. In order to do that, I'm faking the Api response to be:
apiCall.mockImplementation(
() => Promise.reject({ error: 'This is my error' }),
);
However, when mocking the response in this way, I am not able to make it execute before the test case is evaluated. Is there any way to wait for that response to happen before finishing the test?
I have created a codesandbox as simple as I can showing the issue. Since seems that codesandbox does not allow to use jest.mock, I'm just making the original API call to return Promise.reject.
https://codesandbox.io/s/6y0rn74mzw
The behaviour is simple: A text "No error" and a button, that when clicked it calls to the API method that automatically returns Promise.reject. In the response, we change the text to "There is an error". The first test just looks for the word 'error' to make the test pass and show the full evaluation of the code (the test stops if something fails), and the second test is the test I would expect to pass if the correct order was applied.
What would be the way to assure the proper execution order in the test case?
When it comes to dealing with Promises in jest tests, what I've done is as follows:
it('test script description', (done) => {
apiCall()
.then((response) => {
// Verify the response from the promise
done();
});
});
I'm obviously not saying that this is the best solution (perhaps someone can point you in a better direction) but it's the only one that worked for me!
So the solution is to use setImmediate.
If I change the test case to be:
it("should pass but fails due to execution order", done => {
console.log("-----------");
expect(true).toBe(true);
const wrapper = mount(<App />);
wrapper.find("button").simulate("click");
setImmediate(() => {
const newWrapper = wrapper.update();
expect(newWrapper.html()).toContain("There is an error");
done();
});
console.log("Third");
console.log("-----------");
});
It passes.
A good explanation here: https://github.com/kentcdodds/react-testing-library/issues/11

Wait for an own function (which returns a promise) before tests are executed

I'm new to cypress and am trying to figure out how things work.
I have my own function (which calls a test controller server to reset the database). It returns a promise which completes when the DB have been successfully resetted.
function resetDatabase(){
// returns a promise for my REST api call.
}
My goal is to be able to execute it before all tests.
describe('Account test suite', function () {
// how can I call resetDb here and wait for the result
// before the tests below are invoked?
it('can log in', function () {
cy.visit(Cypress.config().testServerUrl + '/Account/Login/')
cy.get('[name="UserName"]').type("admin");
cy.get('[name="Password"]').type("123456");
cy.get('#login-button').click();
});
// .. and more test
})
How can I do that in cypress?
Update
I've tried
before(() => {
return resetDb(Cypress.config().apiServerUrl);
});
But then I get an warning saying:
Cypress detected that you returned a promise in a test, but also invoked one or more cy commands inside of that promise
I'm not invoking cy in resetDb().
Cypress have promises (Cypress.Promise), but they are not real promises, more like duck typing. In fact, Cypress isn't 100% compatible with real promises, they might, or might not, work.
Think of Cypress.Promise as a Task or an Action. They are executed sequentially with all other cypress commands.
To get your function into the Cypress pipeline you can use custom commands. The documentation doesn't state it, but you can return a Cypress.Promise from them.
Cypress.Commands.add('resetDb', function () {
var apiServerUrl = Cypress.config().apiServerUrl;
return new Cypress.Promise((resolve, reject) => {
httpRequest('PUT', apiServerUrl + "/api/test/reset/")
.then(function (data) {
resolve();
})
.catch(function (err) {
reject(err);
});
});
});
That command can then be executed from the test itself, or as in my case from before().
describe('Account', function () {
before(() => {
cy.resetDb();
});
it('can login', function () {
// test code
});
})
You can use cy.wrap( promise ), although there might still be a bug where it never times out (haven't tested).
Otherwise, you can use cy.then() (which is undocumented, can break in the future, and I'm def not doing any favors by promoting internal APIs):
cy.then(() => {
return myAsyncFunction();
});
You can use both of these commands at the top-level of spec like you'd use any command and it'll be enqueued into cypress command queue and executed in order.
But unlike cy.wrap (IIRC), cy.then() supports passing a callback, which means you can execute your async function at the time of the cy command being executed, not at the start of the spec (because expressions passed to cy commands evaluate immediately) --- that's what I'm doing in the example above.

Categories

Resources