Dynamically create tests with cy.task

Viewed 1334

I'd like to generate identical tests with variable data in Cypress. The idea is that testers can create new folders in the fixtures folder, and these folders will automatically be picked up and used to generate new tests.

I've created this snippet in my plugins/index.js. When cy.task('getAllDirectories', 'someURL') is called it will give me a list of all sub-directories inside someURL.

const { readdirSync, lstatSync } = require('fs');
const { join } = require('path');
const _ = require('lodash');

const isDirectory = source => lstatSync(source).isDirectory();

module.exports = (on, config) => {
  on('task', {
    getAllDirectories(source) {
      const fullSource = `${process.cwd()}/cypress/${source}`;

      return readdirSync(fullSource)
        .map(name => join(fullSource, name))
        .filter(isDirectory)
        .map(name => _.last(name.split('/')));
    },
  });
};

This seems to work just fine, I've managed to call it successfully inside it() and before() in Cypress. The problem however is that since these dynamically generated tests are the only ones in this file, this code inside my context doesn't run at all.

let TESTS = [];

  before(() => {
    cy.task('getAllDirectories', '').then((output) => {
      TESTS = output;
      cy.log(TESTS);
    });
  });

Even when I add a dummy test like it('dummy', () => {}), the TESTS variable is set to the new name array, but it's too late to generate tests, when I try to iterate it below the before method.

TESTS.forEach((TEST) => {
    it(`Validates request: ${TEST}`, () => {
      ...

So I figured I need to call cy.task outside of a test or before hook, however putting it only inside context() says that cy.task must be ran inside a test.

1 Answers

Ok, I had almost similar requirement like that as I said in comment. And I found that there is no straight way to do that in cypress.

So I did it in indirect way but still target can be achieved, may be not 100% nice solution.

I made script which gathers necessary info and export data as json in cypress/fixtures. I will write steps as psuedo-code:

Let say file named: load-test-data.ts

1. Search for all spec files in my project
2. Find directory having data in each spec file's directory
3. Build object of information which contains:
  {
     [specFilePath]: {
       componentName,
       data,
     }
  }
where 'data' is data for which I want to generate tests.
4. Generate JSON and save in cypress/fixtures/test-data.json

Then in my test utility (which generates tests)

describe('Should test component', () => {

  const path = Cypress.spec.relative;
  const fixtureData = require('../../../cypress/fixtures/test-data.json');

  const info = fixtureData[path];

  info.data.forEach((datum) => {
    it(`Should pass test for ${datum}`, () => {
      cy.visit(`http://localhost:9001/?page=${datum}`); // this is not real, just for demo purpose!!

      // and do something more
    });
  });

});

And then when I wanna run cypress, I do:

#!/usr/bin/env bash

# Generate fixture which will contain test-data to generate tests
./node_modules/.bin/ts-node  load-test-data.ts

# Run cypress
./node_modules/.bin/cypress run

I hope this helps!

Related