We have an UI development library consisting of widgets built on top of Angular JS. Let's pick "header-widget" as an example - a header container built with Angular JS, but with specific functionality on top if it.
Say the HTML code of this widget will look like this:
<header class="my-header">
<div ng-if="configuration.hasTitle">
<h1 class="my-header-title-text">
<span class="my-header-title-text">This is a main title</span>
<span class="my-header-subtitle-text">This is a subtitle</span>
</h1>
</div>
</header>
I can create an unit/integration test using Karma i.e. at one point I will have something like this:
element = angular.element("<header config=\"config\"></header>");
$compile(element)(myScope);
myScope.$digest();
expect(element.find(".my-header-title-text").text().trim()).toBe("This is a main title");
and I can create an end to end test using Protractor i.e. at one point I will have something like this:
describe('Some end to end spec', function () {
it('should have the right title', function () {
let title = element(by.css(".my-header .my-header-title-text"));
expect(title.getText()).toMatch("This is a main title");
});
});
Suppose the developers change the header and the new class for the title becomes "my-header-MAIN-title-text". I would have to go to all places in unit/integration tests as well as in the end to end tests to fix that.
(For the sake of this example, the change is trivial and in theory can be encapsulated by having selectors in separate files, but in practice I speak about bigger changes in the DOM structure of these widgets, etc.)
I want to build a test library - like a test API - on top of the widgets. An encapsulation layer that would offer me things like header.getTitle() and header.getSubtitle() - that I can use in both unit/integration (Karma) as well as in the end to end world (Protractor). This way, if a change like the one mentioned above will occur, I have to go in one place, fix the implementation of the "header.getTitle" and none of the tests should care about.
To do so, I have created something like this (using TypeScript):
import $ from "jquery";
export class MyHeaderImpl implements MyHeadear {
private selector;
constructor(element) {
this.selector = $(element);
}
getTitle(): string {
return this.selector.find(".my-header-title-text").text().trim();
}
getSubtitle(): string {
return this.selector.find(".my-header-subtitle-text").text().trim();
}
}
It works fine for my unit/integration tests (Karma):
element = angular.element("<header config=\"config\"></header>");
$compile(element)(myScope);
myScope.$digest();
const header = ComponentFactory.createHeader(element);
expect(header.getTitle()).toBe("This is a main title");
However, it will not work on Protractor:
describe('Some end to end spec', function () {
it('should have the right title', function () {
let element = element(by.css(".my-header .my-header-title-text"));
const header = ComponentFactory.createHeader(element);
expect(title.getText()).toMatch("This is a main title");
});
});
It throws the following exception
Failed: jquery_1.default is not a function
I am using TypeScript in the test library, as well as with my Protractor tests.
I can replace the jQuery $ with Protractor's element in my test library, but then I would force the unit/integration tests to run against a browser, which will defeat their purpose of being fast.
Does anyone knows how can I create such a test API library that can be used both by Karma tests, as well as by Protractor tests?
One of the best descriptions I could find here on Stack Overflow, but it does not answer my question.