简体   繁体   中英

Cypress Typescript: how to store a variable that can be used in the afterEach teardown?

I have test cases that store data in a variable at the start for it to be used throughout a test. It works fine during the test and can be called up until the very last step of the test before the teardown, but when I try to use it in the @afterEach teardown that runs at the end of every test to execute any global clean up commands, the variable shows as empty and has nothing stored in it anymore. It seems the variable gets reset unexpectedly.

The reason I want to run it in the teardown is to ensure that stored data is accessed even if the test case fails before it completes to the very end (thus ensuring the data gets collected in the teardown). How can I get a variable to remain stored properly into the teardown of a Cypress test?

I have tried using a static variable in a class, but that doesn't seem to work.

During each test case, a method stores the data of a user and locks it in a session so it can't be used by other tests running in parallel until it is released from the session.

class myUser {
  static user;

  public setUser(params: object): void {
    myUser.user = setAndLockUser(params);
  }

  public releaseLockedUser(): void {
    if (myUser.user == undefined) return;
    releaseTheUserLock(myUser.user);
  }
}

At the end of the test case, I want to ensure the session of the user is removed so the user is no longer locked in a session and can be available for test cases yet to run. So we add releaseUser to the afterEach method:

afterEach(() => {
  myUser.releaseLockedUser();
});

This is where the issue of the stored variable not being recognized is encountered. Throughout the test, the user variable is stored successfully, but during the afterEach teardown the variable is empty and the session cannot be cleared correctly.

Please read Using after or afterEach hooks

Anti-Pattern: Using after or afterEach hooks to clean up state.

The same would apply for any use of state if the test case fails before it completes

Why don't you provide an explicit example of what you want to do, maybe can provide an alternative.


Following the guidelines given by Cypress, you would perform releaseLockedUser() in a beforeEach() rather in an afterEach() which might not be called if the test fails.

That way each test sees a clean static user value.

You could store your values in a Cypress environment variable and reset the state in the afterEach() . Please keep reading after this code example .

class myUser {
  public setUser(params: object): void {
    Cypress.env('user', setAndLockUser(params);
  }

  public releaseLockedUser(): void {
    if (Cypress.env('user') {
      releaseTheUserLock(Cypress.env('user'));
    }
  }
}
...
afterEach(() => {
  /**
   * the `.then()` may not be necessary or feasible, but using to show 
   * how you should be careful to clear the environment variable after
   * you're sure that you've released your locked user.
   */
  myUser.releaseLockedUser().then(() => {
    Cypress.env('user', undefined);
  });
});

While the article Fody references is directly from Cypress, and does make some compelling points, I still believe there is a place for planned uses of after and afterEach . Is it better to use before or beforeEach when you can? Absolutely. But if your case truly calls for resetting state after test runs, then you should feel empowered to use it. With all of that said , in your use case, I'm not sure you need to use an afterEach() . Instead, you could pass in your user as an environment variable in the test, and check if the user is locked in your beforeEach() .

describe('some tests', () => {
  beforeEach(() => {
    // The below function should take `Cypress.env('user')` and check if the user is locked
    // If the user is locked, release the lock.
    releaseTheUserLock();
  });

  it('some test', { env: { user: 'foo' } }, () => {
    // some test that uses the user.
    // user can be reference by `Cypress.env('user')`
  })
});
...
// Additionally, I like to make functions that simplify passing in that environment variable --
const user = (user: string) => {
  return { env: { user } };
});
// used in the following way
it('some test', user('foo'), () => {});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM