A
A
Alexey Nikolaev2019-10-22 18:34:18
JavaScript
Alexey Nikolaev, 2019-10-22 18:34:18

Is it possible to generate tests in Jest one by one, dynamically?

Good evening.
There is jest, puppeteer and a link in the form of jest-puppeteer. There is a list of URLs (several dozens) that you want to test for http status, so that it is 200 ok. To do this, I wrote the necessary code, which generates an assertion (it) for each url on the fly. It works, but it's bad. I'll give you the code right now.

spoiler
const assertStatus = require('./status');

// cards.js
// Это тест, вызывается в index.js так: assertions.cards({ ... });
// jest настроен обрабатывать только один файл, т.е. пишу jest /tests/index.js
module.exports = cards => {
  const cardsGenerator = generateCards();
  
  describe('all cards should have 200 ok and adding to basket', () => {
    jest.setTimeout(50000);

    generateTests(cardsGenerator);
  });

  // Генерирует тесты, рекурсивно
  function generateTests(generator) {
    const generated = generator.next();

    if(generated.done) {
      return false;
    }

    const card = generated.value;
    const testTitle = `card with type '${card.type}' and url '${card.url}' should have 200 ok`;

    assertStatus(card.url, 200, testTitle);

    generateTests(generator);
  };

  // Просто генератор, который обходит массив карточек и отдает одну за другой
  function* generateCards() {
    for(const card of cards) {
      if(!card.type || !card.urls) {
        continue;
      }

      for(const urlIndex in card.urls) {
        const url = card.urls[urlIndex];
        yield {
          type: card.type,
          url,
        };
      }
    }

    return null;
  }
};

// assertions/status.js
const actions = require('../actions');

module.exports = (url, status = 200, testTitle = null) => {
  if(!testTitle) {
    testTitle = `url '${url}' should have status ${status}`;
  }

  return describe('assert.status', () => {
    let lastResponse;
    let page;

    beforeAll(async () => {
      page = await browser.newPage();
      await page.setRequestInterception(true);

      // Это просто для того, чтобы ускорить загрузку страницы, разрешаем только document реквесты
      page.on('request', async request => actions.denyAllExceptDocument()(request));

      [lastResponse] = await Promise.all([
        page.goto(url, {
          waitUntil: 'load',
        }),
      ]);
    });

    it(testTitle, async () => {
      await expect(lastResponse.status()).toEqual(status);
    });
  });
};

The problems are as follows:
Firstly, all this is processed by the jest bundle and immediately. That is, the cycle passes, and the gesture begins to process all statements as one - it thinks for a long time, and then immediately spits out the result of all statements, or errors.
Secondly, it eats up a lot of memory and is simply inconvenient - you don't see which statement (it) is currently being checked.
If you refuse dynamic generation and throw it into the code manually, everything works as it should - the gesture will execute it separately and for each it will dynamically show the result in the console, right away.
If there was some callback in the docks of the gesture that would only be called after the statement (it) was executed, I could generate a new test in this callback, but there is no such thing in the docks.
How to be, what to do?
Thanks in advance.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
G
grinat, 2019-10-22
@grinat

Well, duck generate files before starting the test https://nodejs.org/api/fs.html And you will see everything, before starting, delete the old ones, generate new ones, then run the shit.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question