2

I'm creating API tests with async-await using Supertest and Mocha.

In the accountsData.js file I created a function to generate random test accounts.

In the accountsHelper.js file I created a function to create unlimited accounts using a while loop

When I run tests on the post_accounts.js file, the first account is created successfully, but from the second account, the data generated in the accountsData.js file is already repeated.

Why isn't data randomly generated when I create more than one account using data from the accountsData.js file?

accountsData.js

const casual = require('casual');


function randomAccount() {
  return {
    'email': casual.email,
    'password': '123456',
  };
}

module.exports = {
  randomAccount,
};

accountsHelper.js

const request = require('supertest');
const commonData = require('../data/commonData');

/* eslint-disable no-console */

const accountList = [];
let counterAccounts;


module.exports = {

  async createAccount(account, accountsToCreate = 2, validateResponse = true) {
    counterAccounts = 0;
    while (counterAccounts < accountsToCreate) {
      try {
        const res = await request(commonData.environment.staging)
          .post(commonData.endpoint.accounts)
          .send(account);
        if (validateResponse === true) {
          if (res.status === commonData.statusCode.ok) {
            accountList.push(res.body);
          } else {
            throw new Error('Email already exists\n\n' + JSON.stringify(res.body, null, ' '));
          }
        } else {
          return res.body;
        }
      } catch (err) {
        console.log(err);
      }
      counterAccounts++;
    }
    return accountList;
  },
};

post_accounts.js

const accountsData = require('../../data/accountsData');
const accountsHelper = require('../../helpers/accountsHelper');
const account = accountsData.randomAccount();

describe('Create accounts with email and password', () => {
  context('valid accounts', () => {
    it('should create an account successfully', async() => {
      const res = await accountsHelper.createAccount(account);
      // eslint-disable-next-line no-console
      console.log(res);
    });
  });
});

API response:

  Create accounts with email and password
    valid accounts
Error: Email already exists

{
 "error": {
  "statusCode": 422,
  "name": "ValidationError",
  "message": "The `account` instance is not valid. Details: `email` Email already exists (value: \"Lemuel.Lynch@Susan.net\").",
  "details": {
   "context": "account",
   "codes": {
    "email": [
     "uniqueness"
    ]
   },
   "messages": {
    "email": [
     "Email already exists"
    ]
   }
  }
 }
}
    at Object.createAccount (/Users/rafael/Desktop/projects/services/test/helpers/accountsHelper.js:24:19)
    at process._tickCallback (internal/process/next_tick.js:68:7)
[ { 'privacy-terms': false,
    'created-date': '2019-08-24T10:00:34.094Z',
    admin: false,
    isQueued: false,
    lastReleaseAttempt: '1970-01-01T00:00:00.000Z',
    'agreed-to-rules': { agreed: false },
    email: 'Lemuel.Lynch@Susan.net',
    id: '5d610ac213c07d752ae53d91' } ]
      ✓ should create an account successfully (2243ms)


  1 passing (2s)
Rafael C.
  • 2,245
  • 4
  • 29
  • 45

2 Answers2

-1

The code that you posted doesn't correspond to the code that you're describing in prose.

However, I tested your accountsData.js file, in the way that your words (but not your code) say that you're using it, and it works fine.

// main.js

const { createPerson } = require(__dirname + '/accountsData')

console.log(createPerson())
console.log(createPerson())
console.log(createPerson())
console.log(createPerson())
console.log(createPerson())

Output from running it once:

$ node main.js
{ email: 'Anne_Ebert@Macie.com', password: '123456' }
{ email: 'Manley.Lindgren@Kshlerin.info', password: '123456' }
{ email: 'McClure_Thurman@Zboncak.net', password: '123456' }
{ email: 'Breitenberg.Alexander@Savannah.com', password: '123456' }
{ email: 'Keely.Mann@Stark.io', password: '123456' }

And again:

$ node main.js
{ email: 'Destany_Herman@Penelope.net', password: '123456' }
{ email: 'Narciso_Roob@gmail.com', password: '123456' }
{ email: 'Burnice_Rice@yahoo.com', password: '123456' }
{ email: 'Roma_Nolan@yahoo.com', password: '123456' }
{ email: 'Lilla_Beier@yahoo.com', password: '123456' }

Nothing in the code that you posted is actually requiring or using accountsData.js. If you change your code to use it, I think you'll see, like I do, that it works.

Andrew Koster
  • 1,550
  • 1
  • 21
  • 31
  • Your first output doesn't seem to make sense. 1. The **createAccount** function I posted should create 2 accounts, your output only creates one. 2. You are running the tests directly from the **accountsData.js** file, but you must run the tests from the **post_accounts.js** file – Rafael C. Aug 28 '19 at 20:16
  • No, your code creates one account. My code creates 5 accounts. The problem is that you're only calling createPerson once, so that's why you're only getting one person. – Andrew Koster Aug 28 '19 at 20:34
  • You're calling this once, at the top level of your file: `const account = accountsData.createPerson()`. You need to call it inside your `while` loop, if you want it to be called more than once (and therefore generate more than one person). – Andrew Koster Aug 28 '19 at 20:35
  • It doesn't make sense for a method called `createAccount` to have an `account` parameter, unless you want it to copy data from that existing account (I don't think that's what you are trying to do). – Andrew Koster Aug 28 '19 at 20:36
  • I'm doing just that (running my test inside the while loop). 1. The main function for creating accounts is in the **accountsHelper.js** file (Note that the loop in this function should rotate 2 times.). 2. Observe the **API response**, the function is running twice, but at each iteration the same user is created – Rafael C. Aug 28 '19 at 20:55
  • No, your code doesn't do what you say it does. You're confused because you have methods and variables with misleading names. – Andrew Koster Aug 28 '19 at 20:59
  • Look at this: `const account = accountsData.createPerson()`. Why are you calling a method called `createPerson`, and assigning the return value to something called `account`? If it's creating an account, the method should be called `createAccount`. If it's creating a person, the variable that you're assigning the result to should be called `person`. – Andrew Koster Aug 28 '19 at 21:00
  • I can update this, but the name of the functions is irrelevant – Rafael C. Aug 28 '19 at 21:05
  • It's irrelevant to the instructions that the computer will execute. It's entirely relevant to your understanding of your own code. – Andrew Koster Aug 28 '19 at 21:06
  • Anyway, if you just want it to work, call the method that creates your `person` object inside of the loop (multiple times) instead of doing it outside of the loop (once). – Andrew Koster Aug 28 '19 at 21:07
  • Andrew, I updated my code, I think it's better to understand, sorry for that. You mentioned that I need to call the `randomAccount` function within the while loop, but that's just what I don't want. I want to pass the `randomAccount` function as an argument to the `createAccount` function (where the while loop exists). You also mentioned that my test is just creating one account, not true. My test is creating 2 accounts as expected, but the `randomAccount` function is always returning the same email (and this should be dynamic because I'm using the `casual` library) – Rafael C. Aug 29 '19 at 20:31
-1

Problem is, you are generating the random account and storing it in a variable 'post_accounts.js(line 3)'. So, when you create an account, you are using the same payload to create multiple accounts, which obviously throws an error.

I just modified the accountHelper to properly handle your scenario. Hope this helps.

Note: The code is not tested, I just wrote it from my mind. Please test and let me know if it works.

// accountsHelper.js

const request = require('supertest');
const commonData = require('../data/commonData');
const accountsData = require('../../data/accountsData');
/* eslint-disable no-console */

const accountList = [];

module.exports = {

  async createAccount(account, accountsToCreate = 1, validateResponse = true) {
    // creates an array of length passed in accountsToCreate param
    return (await Promise.all(Array(accountsToCreate)
      .fill()
      .map(async () => {
        try {
          const res = await request(commonData.environment.staging)
            .post(commonData.endpoint.accounts)
            // takes account if passed or generates a random account
            .send(account || accountsData.randomAccount());

          // validates and throw error if validateResponse is true
          if (validateResponse === true && (res.status !== commonData.statusCode.ok)) {
            throw new Error(
              'Email already exists\n\n' +
              JSON.stringify(res.body, null, ' ')
            );
          }

          // return response body by default
          return res.body;
        } catch (e) {
          console.error(e);
          // return null if the create account service errors out, just to make sure the all other create account call doesnt fail
          return null;
        }
      })))
      // filter out the null(error) responses
      .filter(acc => acc);
  }
};


//post_accounts.js

const accountsHelper = require('../../helpers/accountsHelper');
const accountsData = require('../../data/accountsData');

const GENERATE_RANDOM_ACCOUNT = null;

describe('Create accounts with email and password', () => {
  context('valid accounts', () => {
    it('should create an account successfully', async () => {
      const result = await accountsHelper.createAccount();

      expect(result.length).toEquals(1);
    });

    it('should create 2 accounts successfully', async () => {
      const result = await accountsHelper.createAccount(GENERATE_RANDOM_ACCOUNT, 2);

      expect(result.length).toEquals(2);
    });

    it('should not create duplicate accounts', async () => {
      const account = accountsData.randomAccount();
      // here we are trying to create same account twice
      const result = await accountsHelper.createAccount(account, 2);

      // expected result should be one as the second attempt will fail with duplicate account
      expect(result.length).toEquals(1);
    });
  });
});
ajai Jothi
  • 2,284
  • 1
  • 8
  • 16