Skip to content

Commit

Permalink
Merge pull request #5 from oktadeveloper/mraible-ui-tests
Browse files Browse the repository at this point in the history
Add Ionic PWA unit and e2e tests
  • Loading branch information
Matt Raible committed May 2, 2018
2 parents d0e8419 + 7042249 commit 5c10e6d
Show file tree
Hide file tree
Showing 19 changed files with 6,833 additions and 2,309 deletions.
2 changes: 1 addition & 1 deletion README.md
@@ -1,4 +1,4 @@
# Crypto PWA with Holdings Data in Okta
# Cryptocurrency PWA with Holdings Data in Okta

This example app shows how to use Okta's Java SDK to store cryptocurrency holdings as a custom user attribute.

Expand Down
30 changes: 30 additions & 0 deletions crypto-pwa/e2e/pages/add-holding.po.ts
@@ -0,0 +1,30 @@
import { $, by, element } from 'protractor';
import { Page } from './app.po';

export class AddHoldingPage extends Page {
cryptoCode = element.all(by.css('input[type=text]')).first();
displayCurrency = element.all(by.css('input[type=text]')).get(1);
amountHolding = element.all(by.css('input[type=number]'));
addHoldingButton = element(by.buttonText('Add Holding'));
pageTitle = $('ion-title');

setCryptoCode(code) {
this.cryptoCode.sendKeys(code);
}

setCurrency(currency) {
this.displayCurrency.sendKeys(currency);
}

setAmount(amount) {
this.amountHolding.sendKeys(amount);
}

clickAddHoldingButton() {
this.addHoldingButton.click();
}

getPageTitle() {
return this.pageTitle;
}
}
12 changes: 12 additions & 0 deletions crypto-pwa/e2e/pages/app.po.ts
@@ -0,0 +1,12 @@
import { browser } from 'protractor';

export class Page {

navigateTo(destination) {
return browser.get(destination);
}

getTitle() {
return browser.getTitle();
}
}
11 changes: 11 additions & 0 deletions crypto-pwa/e2e/pages/home.po.ts
@@ -0,0 +1,11 @@
import { by, element } from 'protractor';
import { Page } from './app.po';

export class HomePage extends Page {
addCoinsButton = element(by.buttonText('Add Coins'));
deleteButton = element.all(by.css('button[color=danger]')).last();

clickAddCoinsButton() {
this.addCoinsButton.click();
}
}
59 changes: 59 additions & 0 deletions crypto-pwa/e2e/pages/login.po.ts
@@ -0,0 +1,59 @@
import { browser, by, element } from 'protractor';
import { Page } from './app.po';

export class LoginPage extends Page {
username = element(by.name('username'));
password = element(by.name('password'));
oktaLoginButton = element(by.css('input[type=submit]'));
loginButton = element(by.css('#login'));
logoutButton = element(by.css('#logout'));
header = element(by.css('ion-title'));

getHeader() {
return this.header.getText();
}

setUserName(username) {
this.username.sendKeys(username);
}

getUserName() {
return this.username.getAttribute('value');
}

clearUserName() {
this.username.clear();
}

setPassword(password) {
this.password.sendKeys(password);
}

getPassword() {
return this.password.getAttribute('value');
}

clearPassword() {
this.password.clear();
}

login(username: string, password: string) {
// Entering non angular site, tell webdriver to switch to synchronous mode.
browser.waitForAngularEnabled(false);
this.username.isPresent().then(() => {
this.username.sendKeys(username);
this.password.sendKeys(password);
this.oktaLoginButton.click();
}).catch(error => {
browser.waitForAngularEnabled(true);
});
}

clickLoginButton() {
return this.loginButton.click();
}

logout() {
return this.logoutButton.click();
}
}
26 changes: 26 additions & 0 deletions crypto-pwa/e2e/spec/app.e2e-spec.ts
@@ -0,0 +1,26 @@
import { Page } from '../pages/app.po';
import { browser, protractor, ExpectedConditions as ec } from 'protractor';

describe('App', () => {
let page: Page;

beforeEach(() => {
page = new Page();
});

describe('default screen', () => {
beforeEach(() => {
page.navigateTo('/#/home');
});

it('should redirect to login', () => {
browser.wait(ec.urlContains('/#/login'), 5000);
});

it('should have the correct title', () => {
page.getTitle().then(title => {
expect(title).toEqual('Cryptocurrency PWA with Authentication');
});
});
});
});
47 changes: 47 additions & 0 deletions crypto-pwa/e2e/spec/login.e2e-spec.ts
@@ -0,0 +1,47 @@
import { browser, element, by, protractor, ExpectedConditions as ec } from 'protractor';
import { LoginPage } from '../pages/login.po';

describe('Login', () => {

let loginPage;

beforeAll(() => {
loginPage = new LoginPage();
loginPage.navigateTo('/');
browser.waitForAngular();
});

it('should show a login button', () => {
expect(loginPage.getHeader()).toMatch(/Login/);
expect(loginPage.loginButton.isPresent());
});

it('should fail to log in with bad password', () => {
loginPage.clickLoginButton();
loginPage.login('admin', 'foo');
const error = element.all(by.css('.infobox-error')).first();
browser.wait(ec.visibilityOf(error), 2000).then(() => {
expect(error.getText()).toMatch("Sign in failed!");
});
});

it('should log in successfully with demo account', () => {
loginPage.clearUserName();
loginPage.setUserName(process.env.E2E_USERNAME);
loginPage.clearPassword();
loginPage.setPassword(process.env.E2E_PASSWORD);
loginPage.oktaLoginButton.click();

const welcome = /Welcome/; // Use /Welcome, First Last/ if you want to verify full name
const success = element.all(by.css('h1')).first();
browser.wait(ec.visibilityOf(success), 5000).then(() => {
expect(success.getText()).toMatch(welcome);
});
});

it('should log out successfully', () => {
loginPage.logout();
browser.wait(ec.urlContains('/#/login'), 2000);
expect(loginPage.loginButton.isPresent());
})
});
66 changes: 66 additions & 0 deletions crypto-pwa/e2e/spec/manage.e2e-spec.ts
@@ -0,0 +1,66 @@
import { browser, element, by, protractor, ExpectedConditions as ec, $ } from 'protractor';
import { LoginPage } from '../pages/login.po';
import { AddHoldingPage } from '../pages/add-holding.po';
import { HomePage } from '../pages/home.po';

describe('Manage Holdings', () => {

let loginPage, homePage, addHoldingPage;

beforeAll(() => {
loginPage = new LoginPage();
homePage = new HomePage();
addHoldingPage = new AddHoldingPage();
loginPage.navigateTo('/');
browser.waitForAngular();
});

beforeEach(() => {
loginPage.clickLoginButton();
loginPage.login(process.env.E2E_USERNAME, process.env.E2E_PASSWORD);
loginPage.oktaLoginButton.click();

browser.wait(ec.urlContains('home'), 5000);
});

afterEach(() => {
loginPage.logout();
});

it('should add and remove a holding', () => {
homePage.clickAddCoinsButton();

browser.wait(ec.urlContains('add-holding'), 1000);

addHoldingPage.setCryptoCode('BTC');
addHoldingPage.setCurrency('USD');
addHoldingPage.setAmount(3);
addHoldingPage.clickAddHoldingButton();

// wait for everything to happen
browser.wait(ec.urlContains('home'), 5000);

// verify message is removed and holding shows up
element.all(by.css('.message')).then((message) => {
expect(message.length).toBe(0);
});

// wait for holding to show up
const addedHolding = element.all(by.css('ion-item')).last();
browser.wait(ec.presenceOf(addedHolding), 5000).then(() => {

// delete the holding - https://forum.ionicframework.com/t/move-ion-item-sliding-by-protractor/106918
browser.actions().mouseDown(addedHolding)
.mouseMove({x: -50, y: 0})
.mouseMove({x: -50, y: 0})
.mouseMove({x: -50, y: 0})
.mouseUp()
.perform();

homePage.deleteButton.click();
element.all(by.css('.message')).then((message) => {
expect(message.length).toBe(1);
});
});
});
});
12 changes: 12 additions & 0 deletions crypto-pwa/e2e/tsconfig.e2e.json
@@ -0,0 +1,12 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"typeRoots": [
"../node_modules/@types"
]
}
}

0 comments on commit 5c10e6d

Please sign in to comment.