admin管理员组

文章数量:1415120

I am trying to repeat a certain action in cypress defined in doTheAction and then get the results of those repeated actions. When I try Promise.all it immediately resolves to an array of undefined

describe("some test", () => {
  it("for each", () => {
    const data = { a: 1, b: 2 };
    Promise.all(
      Object.entries(data.en).map(([key, value]) =>
        doTheAction(value).then(result => [key, result])
      )
    ).then(result => {
      debugger;
      // array of undefined before the browser did anything
      console.log(result);
    });
  });
});
const doTheAction = text => {
  cy.visit(
    ""
  );
  cy.get("some input").type(text);
  return cy
    .get("the result")
    .then(result => result[0].innerText);
};

When I try to chain the actions I get undefined for results when the second action is finished:

describe("some test", () => {
  it("for each", () => {
    const data = { a: 1, b: 2 };
    Object.entries(data).reduce(
      (results, [key, value]) =>
        results.then(results =>
          doTheAction(value).then(
            result =>
              //results is undefined after the second action
              results.concat([[key, result]]) //current result
          )
        ),
      Promise.resolve([]) //initial results
    );
  }).then(results => {
    //never gets here
    console.log(results);
  });
});
const doTheAction = text => {
  cy.visit("");
  cy.get("some input").type(text);
  return cy
    .get("the result")
    .then(result => result[0].innerText);
};

Either with Promise.all or chaining the promises the actions will run in the correct order (cypress schedules them and runs them in order) but I don't see how it's possible to get a result out of it.

I am trying to repeat a certain action in cypress defined in doTheAction and then get the results of those repeated actions. When I try Promise.all it immediately resolves to an array of undefined

describe("some test", () => {
  it("for each", () => {
    const data = { a: 1, b: 2 };
    Promise.all(
      Object.entries(data.en).map(([key, value]) =>
        doTheAction(value).then(result => [key, result])
      )
    ).then(result => {
      debugger;
      // array of undefined before the browser did anything
      console.log(result);
    });
  });
});
const doTheAction = text => {
  cy.visit(
    "https://my.site"
  );
  cy.get("some input").type(text);
  return cy
    .get("the result")
    .then(result => result[0].innerText);
};

When I try to chain the actions I get undefined for results when the second action is finished:

describe("some test", () => {
  it("for each", () => {
    const data = { a: 1, b: 2 };
    Object.entries(data).reduce(
      (results, [key, value]) =>
        results.then(results =>
          doTheAction(value).then(
            result =>
              //results is undefined after the second action
              results.concat([[key, result]]) //current result
          )
        ),
      Promise.resolve([]) //initial results
    );
  }).then(results => {
    //never gets here
    console.log(results);
  });
});
const doTheAction = text => {
  cy.visit("https://my.site");
  cy.get("some input").type(text);
  return cy
    .get("the result")
    .then(result => result[0].innerText);
};

Either with Promise.all or chaining the promises the actions will run in the correct order (cypress schedules them and runs them in order) but I don't see how it's possible to get a result out of it.

Share Improve this question edited Feb 17, 2020 at 14:45 HMR asked Feb 17, 2020 at 14:34 HMRHMR 39.4k25 gold badges98 silver badges174 bronze badges 4
  • See Commands-Are-Not-Promises. Also, unlikely you could cy.visit("https://my.site") in parallel, there is only one iFrame for the app. – Richard Matsen Commented Feb 17, 2020 at 19:28
  • Your 2nd attempt is sequential, looks like it might work if you use [] instead of Promise.resolve([]) as the reducer initial value. – Richard Matsen Commented Feb 17, 2020 at 19:34
  • @RichardMatsen Using array as initial value would cause an error because array doesn't have a then property that is a function. – HMR Commented Feb 18, 2020 at 7:53
  • Actually you it(...).then(...) which is really weird. Not sure what that would do. – Richard Matsen Commented Feb 18, 2020 at 8:09
Add a ment  | 

1 Answer 1

Reset to default 5

Data driven tests are quite easy, one generalized pattern is

const arrayOfTestData = [...];
const arrayOfExpectedResults = [...];  

const functionContainingSingleTest = (dataItem, index) => {

  // Commands that use dataItem, and check arrayOfExpectedResults[index]

}

arrayOfTestData.forEach((dataItem, index) => 
  functionContainingSingleTest(dataItem, index)
);
// After loop, reached before mands finish.

What happens is your test en-queue's the mands within the function, as if you had written them sequentially.


If you want to gather results, it bees more difficult because Commands don't return a usable value. You could try chaining .then(result => results.push(result)), but the problem is any code external to the loop that uses the results array will likely run before the mand sequence finishes.

One way is to set a Cypress alias at the loop end and wait for it.

Test

describe('Data-driven tests', () => {

  it('should wait for results', () => {

    const arrayOfTestData = [1,2,3];
    const results = [];

    const functionContainingSingleTest = (dataItem, index) => {

      cy.visit('app/data-driven.html');
      cy.get('input').type(dataItem);

      cy.get('input').invoke('val')
        .then(result => {
          results.push(result[0]);
        });

      if (index === arrayOfTestData.length -1) {
        // Note, the following line executes before all tests finish, 
        // but is just queueing a mand, which will run after
        // all the tests have pleted
        cy.wrap(true).as('done');  
      }
    }

    arrayOfTestData.forEach((dataItem, index) => 
      functionContainingSingleTest(dataItem, index)
    );

    // After loop, reached before mands finish.
    console.log(results);  // outputs []

    // Wait for the signal 
    cy.get('@done').then(_ => {
      console.log(results);  // outputs ["1", "2", "3"]
    });

  })
})

app/data-driven.html

<input />

本文标签: javascriptHow to repeat actions in cypress and get the result of each actionStack Overflow