4
votes

In my project I am using protractor + jasmine + TypeScript for e2e tests. I have already benefit from TypeScript glory of inheritance in my page object files (for example, I got some BasePageObject class with common methods/objects from which rest of PageObjects are derived). I would like to introduce same approach in my tests. Here example code, which I got right now:

Test suite A [ATest.ts]:

import {
     SomePage,
     LoginPage
} from '../pages';


describe('test suite A', () => {
    let loginPage: LoginPage = new LoginPage();
    let somePage: SomePage = new SomePage();

    beforeAll(() => {
        loginPage.login();
        somePage.navigateTo();
    });

    it('my test 1', () => {
        //test body, assertions etc.
    });

    it('my test 2', () => {
        //test body, assertions etc.
    });
});

Test suite B [BTest.ts]:

import {
     AnotherPage,
     LoginPage
} from '../pages';


describe('test suite B', () => {
    let loginPage: LoginPage = new LoginPage();
    let anotherPage: AnotherPage = new AnotherPage();

    beforeAll(() => {
        loginPage.login();
        anotherPage.navigateTo();
    });

    it('my test 1', () => {
        //test body, assertions etc.
    });

    it('my test 2', () => {
        //test body, assertions etc.
    });
});

As you can see, some of the code is common for both suites. What I would like to achieve is inheritance in my TCses, to write them more in Java Style and avoid code duplication (for example):

class BaseTestCase {
    beforeAll() {
        loginAction();
    }
}

class TestA extends BaseTestCase {
     beforeAll() {
         specificStuff();
     }
}

class TestB extends BaseTestCase {
     beforeAll() {
         specificStuff();
     }
}

Is it possible in jasmine?

2
you can create service that manage both beforeAll - Yoav Schniederman
The question is missing details. Are loginPage and anotherPage variables used anywhere else? If they should be instantiated once per specs, they could be moved to a module and be singleton instances, couldn't they? - Estus Flask
Did you figure out a good solution for this? I'm having the same problem/situation myself. - S.Huston
describe is a function, not a class. So it does not have a class based extends. You could use prototype inheritance but I would just create my own class and then have this call describe, something like this answer - Liam

2 Answers

2
votes

You could create a base class and extend it pretty easily then replace the callbacks with functions.

export abstract class BaseTest {
  abstract loginAction(): void;
  abstract specificStuff(): void;
}

export class FooTest extends BaseTest {
  loginAction(): void {
    // does stuff to login
  }
  specificStuff(): void {
    // do tests and expectations
  }
}

In your test:

// Do some importing for FooTest.

describe('test suite A', () => {
  let fooTest = new FooTest();

  beforeAll(fooTest.loginAction);

  it('should do some specific stuff', fooTest.specificStuff);
});

Should you do this?

It is possible to do this; however, is this something you want to do? I imagine your FooTest class method will do some expectations on the test. This is (in my opinion) not a good pattern to follow. Your it blocks should contain your expectations instead of taking it out.

0
votes

This "Jasmine describe override" looks promising and ill give it a try: https://ajsblackbelt.wordpress.com/2016/05/06/jasmine-describe-override/

(This code is not tested yet)

global.myDescribe = function (name, arg1, arg2, suite) {
  describe(name, function){
    _myDescribeLogic(name, arg1, arg2, suite);
  }
};

function _myDescribeLogic(name, arg1, arg2, suite) {
  beforeAll(function (done) {
    // code
  });
  beforeEach(function (done) {
    // code
  });

  afterAll(function (done) {
    // code
  });
  afterEach(function (done) {
    // code
  });
}

Add this in your protractor config file:

onPrepare: 'src/framework/myOnPreapre.js'

And then this should work:

myDescribe('a suite', 'foo', 'bar', function(){
  it('should test a business function', function(){
    // code
  })
})

Don't forget to extend x- and fdescribe, as the article describes.


Why would i like to do that? Because some things are always the same for every test, like a login (yes, expect for the login tests, which are excluded from that). And i don't want copy&waste the necessary before*()'s from file to file.

There should be on place where i define such generell things and i want it to be usable without a mistake (like forgetting something or making errors during copy&paste&modify).

For me its noise to read the same lines of codes over and over again. It makes a test more unreadable. I just want to read the test specific things. Everything else is context. I don't care for the login if the test is about writing and saving a text.

For different reasons i don't like that jasmine/protractor tests are based on standalone files. The tests in one file are for me just a sub suite. The 'real' suite are all my test files.