Skip to content

Commit

Permalink
Merge pull request #29 from xmpp-grid-broker/XGB-155-e2e-overview
Browse files Browse the repository at this point in the history
[#XGB-155] e2e overview
  • Loading branch information
fabianhauser committed May 8, 2018
2 parents 0ce080b + 55f1b8a commit baaeb5b
Show file tree
Hide file tree
Showing 29 changed files with 757 additions and 38 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ node_js:
- "8"
script:
- bash build.bash
- npm run e2e

before_deploy:
- cp -a dist $RELEASE_NAME
Expand Down
4 changes: 3 additions & 1 deletion build.bash
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env bash
set -exu
set -e
set -x
set -u

npm install
npm run ng -- lint
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
version: '2.2'
services:
openfire:
image: xmpp-grid-broker/openfire
image: xmpp-grid-broker/openfire-e2e
build:
context: ./stack/
dockerfile: Dockerfile
context: ./e2e/stack/
dockerfile: Dockerfile-openfire
networks:
- backend
nginx:
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.openfire-admin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ version: '2.2'
services:
openfire:
volumes:
- ./stack/openfire:/var/lib/openfire:rw
- ./stack/openfire:/var/lib/openfire:Z
21 changes: 21 additions & 0 deletions e2e/page-elements/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {by, ElementArrayFinder} from 'protractor';

export class List {
private get listElements(): ElementArrayFinder {
const listElement = this.parentElement.element(by.tagName('xgb-list'));
return listElement.all(by.tagName('xgb-list-item'));
}

async listContent(): Promise<string[]> {
const elements = await this.listElements;
return Promise.all(elements.map(listElement => listElement.getText()));
}

async length(): Promise<number> {
const list = await this.listElements;
return list.length;
}

constructor(readonly parentElement) {
}
}
8 changes: 4 additions & 4 deletions e2e/helpers.ts → e2e/page-elements/spinner.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import {$, browser, element, protractor} from 'protractor';
import {$, browser, protractor} from 'protractor';

export class Helpers {
export class Spinner {
/**
* Returns promise that resolves as soon as no `xgb-spinner`-tags are visible.
*/
static noSpinners(retryMs?: number = 20000): Promise<void> {
static waitOnNone(retryMs: number = 20000): Promise<void> {
const EC = protractor.ExpectedConditions;
return new Promise(resolve => {
setTimeout(() => {
const spinner = $('xgb-spinner');
browser.wait(EC.not(EC.presenceOf(spinner)), retryMs)
.then(() => resolve());
}, 5000); // wait a second to give the spinner time to initialise
}, 200); // wait a moment to give the spinner time to initialise
});
}
}
19 changes: 19 additions & 0 deletions e2e/page-elements/tab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {UrlAddressableComponent} from './urlAddressableComponent';
import {by, element, ElementFinder} from 'protractor';

export abstract class Tab extends UrlAddressableComponent {

abstract get linkText(): string;

get tabElement(): ElementFinder {
return this.parentElement.element(by.tagName('xgb-tabs'));
}

get linkElement(): ElementFinder {
return this.tabElement.element(by.linkText(this.linkText));
}

protected constructor(public parentElement = element(by.tagName('body'))) {
super();
}
}
21 changes: 21 additions & 0 deletions e2e/page-elements/urlAddressableComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {browser} from 'protractor';
import {Spinner} from './spinner';

export abstract class UrlAddressableComponent {

abstract get landingUrl();

get fullUrl() {
return browser.baseUrl + this.landingUrl;
}

/**
* Navigate to {@member fullUrl} and wait until
* the page loads and there are no waiting spinners.
*/
async navigateTo() {
browser.waitForAngularEnabled(false);
await browser.get(this.landingUrl);
await Spinner.waitOnNone();
}
}
12 changes: 4 additions & 8 deletions e2e/page-objects/app.po.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { browser, by, element } from 'protractor';
import {UrlAddressableComponent} from '../page-elements/urlAddressableComponent';

export class AppPage {
navigateTo() {
return browser.get('/');
}

getParagraphText() {
return element(by.css('xgb-root h1')).getText();
export class AppPage extends UrlAddressableComponent {
get landingUrl(): string {
return '/';
}
}
7 changes: 7 additions & 0 deletions e2e/page-objects/create-collection.po.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {UrlAddressableComponent} from '../page-elements/urlAddressableComponent';

export class CreateCollectionPage extends UrlAddressableComponent {
get landingUrl(): string {
return '/topics/new/collection';
}
}
7 changes: 7 additions & 0 deletions e2e/page-objects/create-topic.po.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {UrlAddressableComponent} from '../page-elements/urlAddressableComponent';

export class CreateTopicPage extends UrlAddressableComponent {
get landingUrl(): string {
return '/topics/new/topic';
}
}
119 changes: 114 additions & 5 deletions e2e/page-objects/topics-overview.po.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,118 @@
import {browser} from 'protractor';
import {by, element, ElementFinder} from 'protractor';
import {UrlAddressableComponent} from '../page-elements/urlAddressableComponent';
import {Tab} from '../page-elements/tab';
import {CreateTopicPage} from './create-topic.po';
import {Spinner} from '../page-elements/spinner';
import {CreateCollectionPage} from './create-collection.po';
import {List} from '../page-elements/list';

export class TopicsOverviewPage {
landingUrl = '/topics/root';
type TopicsOverviewTab = TopicOverviewRootCollectionsTab | TopicOverviewAllTopicsTab | TopicOverviewAllCollectionsTab;

navigateTo() {
return browser.get(this.landingUrl);
export class TopicOverviewRootCollectionsTab extends Tab {
get list(): List {
return new List(element(by.tagName('xgb-topics')));
}

get landingUrl(): string {
return '/topics/root';
}

get linkText(): string {
return 'Root Collections';
}

constructor(parentElement?: ElementFinder) {
super(parentElement);
}

}

export class TopicOverviewAllTopicsTab extends Tab {
get list(): List {
return new List(element(by.tagName('xgb-topics')));
}

get landingUrl(): string {
return '/topics/all';
}

get linkText(): string {
return 'All Topics';
}

constructor(parentElement?: ElementFinder) {
super(parentElement);
}
}

export class TopicOverviewAllCollectionsTab extends Tab {
get list(): List {
return new List(element(by.tagName('xgb-topics')));
}

get landingUrl(): string {
return '/topics/collections';
}

get linkText(): string {
return 'All Collections';
}

constructor(parentElement?: ElementFinder) {
super(parentElement);
}
}

export class TopicsOverviewPage extends UrlAddressableComponent {
get landingUrl(): string {
return '/topics';
}

private get elementLocator(): ElementFinder {
return element(by.tagName('xgb-topic-overview'));
}

private _tab: TopicsOverviewTab = undefined;

get tab(): TopicsOverviewTab {
if (this._tab === undefined) {
// create default tab on first call, as the parent element might not be rendered earlier
this._tab = new TopicOverviewRootCollectionsTab(this.elementLocator);
}
return this._tab;
}

set tab(tab: TopicsOverviewTab) {
tab.parentElement = this.elementLocator;
this._tab = tab;
}

async navigateToTab(tab: TopicsOverviewTab): Promise<void> {
this.tab = tab;
await tab.linkElement.click();
return Spinner.waitOnNone();
}

async clickNewTopic(): Promise<CreateTopicPage> {
await this.newTopicButton.click();
await Spinner.waitOnNone();

return new CreateTopicPage();
}

async clickNewCollection(): Promise<CreateCollectionPage> {
await this.newCollectionButton.click();
await Spinner.waitOnNone();

return new CreateCollectionPage();
}

private get newTopicButton(): ElementFinder {
return element(by.cssContainingText('button', 'New Topic'));
}

private get newCollectionButton(): ElementFinder {
return element(by.cssContainingText('button', 'New Collection'));
}

}
20 changes: 7 additions & 13 deletions e2e/routes.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import {browser} from 'protractor';
import {TopicsOverviewPage} from './page-objects/topics-overview.po';
import {Helpers} from './helpers';
import {TopicOverviewRootCollectionsTab} from './page-objects/topics-overview.po';
import {AppPage} from './page-objects/app.po';

browser.waitForAngularEnabled(false);

describe('Routes', () => {
let topicsOverview: TopicsOverviewPage;
it('root should redirect to topics overview', async() => {
const appPage = new AppPage();
await appPage.navigateTo();

beforeEach(() => {
topicsOverview = new TopicsOverviewPage();
});

it('root should redirect to topics overview', async () => {
await browser.get('/');
await Helpers.noSpinners();

expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + topicsOverview.landingUrl);
const destination = new TopicOverviewRootCollectionsTab();
expect(browser.getCurrentUrl()).toEqual(browser.baseUrl + destination.landingUrl);
});
});
4 changes: 4 additions & 0 deletions e2e/stack/Dockerfile-openfire
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM gizmotronic/openfire:4.2.3

ADD openfire /var/lib/openfire

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/usr/lib/jvm/java-8-oracle/jre
1525714705223
1 change: 1 addition & 0 deletions e2e/stack/openfire/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4.2.3
Loading

0 comments on commit baaeb5b

Please sign in to comment.