0

I'm trying to write a test that will run a GET over all items. To do this, I get that list in the before block, then I want to have an it block for each item. I am trying to do this by putting the it block inside itemList.forEach. However, I suspect that the problem here is that the blocks never get registered for the test. How can I run this test as desired?

let token;
let itemList;

describe('GET items/:itemId with Admin', async () => {
  before(async () => {
    // NOTE: item.find({}) returns a promise of a list of all items
    itemList = await item.find({});
    console.log(item[0]._id) // this logs correctly!
    const res = await userLogin(admin);
    token = res.body.accessToken.toString();   
  });

  it('registers initial it test', () => {
    // This test passes and logs the statement
    console.log('first test registered')
    console.log(itemList.length) // successfully logs non-zero value
  })

  await itemList.forEach(async (item) => {
    it('respond with json with a item', () => {
    const itemId = item._id;
    return getItem(itemId, token)
      .then((response) => {
        assert.property(response.body, '_id');
      });
    });
  });
});
swagrov
  • 1,510
  • 3
  • 22
  • 38
  • I don't think `describe` takes a function that returns a promise. – Bergi Jan 04 '18 at 19:10
  • [You cannot use `await` with `forEach`!](https://stackoverflow.com/q/37576685/1048572) – Bergi Jan 04 '18 at 19:10
  • @Bergi I read that post before, but to be honest, I have an existing test suite that uses `async await` and `forEach` for a non-promise array and it works exactly as expected. – swagrov Jan 04 '18 at 20:21
  • Also removing the async/await doesn't change the non-functional behavior of the test. Essentially I think the problem is that when mocha reads over the cases, `itemList` is `[]`, so it doesn't register any of the cases, even though `itemList` is populated as evident by the `console.log` statement – swagrov Jan 04 '18 at 20:38

2 Answers2

0

Afaik the before setup runs before every it test. It doesn't run immediately, and definitely does not wait for anything until you try to iterate your itemList. I think you will need to do either

describe('GET items/:itemId with Admin', async () => {
  let token;
  before(async() => {
    const res = await userLogin(admin);
    token = res.body.accessToken.toString();   
  });

  // a list of all items for which tests should be created
  const itemList = await item.find({});
  console.log(itemList.length) // successfully logs non-zero value

  for (const item of itemList) {
    it('responds with json for item '+item, () => {
    const itemId = item._id;
    return getItem(itemId, token).then((response) => {
      assert.property(response.body, '_id');
    });
  }
});

or

describe('GET items/:itemId with Admin', () => {
  let itemList;
  let token;
  before(async() => {
    [itemList, token] = await Promise.all([
      item.find({}),
      userLogin(admin).then(res => res.body.accessToken.toString())
    ]);
  });

  it('responds with json for every item', () => {
    return Promise.all(itemList.map(item => {
      const itemId = item._id;
      return getItem(itemId, token)
        .then((response) => {
          assert.property(response.body, '_id');
        });
      });
    }));
  });
});
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
-1

This is the solution I ended up with. I ended up putting a new describe block in the before block. The before block results the promise that gives the list of items. There is an it block in the top level so that mocha registers the test in the first place.

describe('GET items/:itemId with Admin', async () => {
  before((done) => {
    Item.find({}).then(async (itemList) => {
      // create the admin user to get the items with
      await createUsers([admin]);
      const res = await userLogin(admin);
      const token = res.body.accessToken.toString();

      itemList.forEach((item, index) => {
        const itemId = item._id;
        describe(`get item number ${index}: _id: ${itemId}`, () => {
          it('responds with item id', () =>
            getItem(item, token)
              .expect(200)
              .then((response) => {
                assert.notProperty(response.body, 'error');
                assert.property(response.body, '_id');
                assert.equal(response.body._id, itemId);
              }));
        });
      });
      done();
    });
  });
  // If there is no it block here, it will not run the before block!
  it(`register the initial it`, () => {
    assert.equal('regression test!', 'regression test!');
  });
});
swagrov
  • 1,510
  • 3
  • 22
  • 38