Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add E2E test for server-side login #312

Merged
merged 1 commit into from Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions test/app/env.js
@@ -0,0 +1,15 @@
/* global process, __dirname */
const dotenv = require('dotenv');
const fs = require('fs');
const path = require('path');
const ROOT_DIR = path.resolve(__dirname, '..', '..');

// Read environment variables from "testenv". Override environment vars if they are already set.
const TESTENV = path.resolve(ROOT_DIR, 'testenv');

if (fs.existsSync(TESTENV)) {
const envConfig = dotenv.parse(fs.readFileSync(TESTENV));
Object.keys(envConfig).forEach((k) => {
process.env[k] = envConfig[k];
});
}
11 changes: 5 additions & 6 deletions test/app/package.json
Expand Up @@ -6,22 +6,21 @@
"scripts": {
"lint": "eslint .",
"watch": "webpack --watch",
"start": "webpack-dev-server",
"start:dev": "yarn start --open",
"start": "node server.js",
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "Apache-2.0",
"dependencies": {
"dotenv": "^7.0.0",
"webpack": "^4.29.6"
},
"devDependencies": {
"@webpack-cli/serve": "^0.1.5",
"dotenv": "^7.0.0",
"express": "^4.17.1",
"source-map-loader": "^0.2.4",
"text-encoding": "^0.7.0",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.2.1"
}
}
1 change: 1 addition & 0 deletions test/app/public/index.html
Expand Up @@ -8,5 +8,6 @@
<script type="text/javascript">
bootstrapLanding();
</script>
<a href="/server">Server-side Login Form</a>
</body>
</html>
40 changes: 40 additions & 0 deletions test/app/public/server/index.html
@@ -0,0 +1,40 @@
<html>
<head>
<link rel="stylesheet" href="/oidc-app.css"/>
</head>
<body class="web-app landing">
<div id="root">
<strong>Server-side Login Form</strong>
<div id="form">
<form method="POST" action="/login">
<label for="issuer">Issuer:</label><input name="issuer" id="issuer" placeholder="issuer" type="text"/><br/>
<label for="username">Username:</label><input name="username" id="username" placeholder="username" type="email"/><br/>
<label for="password">Password:</label><input name="password" id="password" placeholder="password" type="password"/><br/>
<input id="submitBtn" type="submit"/>
</form>
</div>
<div id="results">
<div class="box">
<strong>Status</strong><br/>
<div id="status"></div>
</div>
<div class="box">
<strong>Session Token</strong><br/>
<div id="sessionToken" style="color: green"></div>
</div>
<div class="box">
<strong>Error</strong><br/>
<div id="error" style="color: red"></div>
</div>
</div>
</div>
<script type="text/javascript">
var url = new URL(window.location.href);
['status', 'sessionToken', 'error'].forEach(function(param) {
var value = url.searchParams.get(param);
document.getElementById(param).innerText = value;
});
</script>
<a href="/">Back to SPA app</a>
</body>
</html>
62 changes: 62 additions & 0 deletions test/app/server.js
@@ -0,0 +1,62 @@
/* eslint-disable no-console */

require('./env'); // update environment variables from testenv file

const OktaAuthJS = require('@okta/okta-auth-js');

const util = require('./src/util');
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
}));

app.use(express.static('./public'));

app.use(express.urlencoded());
app.post('/login', function(req, res) {
const issuer = req.body.issuer;
const username = req.body.username;
const password = req.body.password;
let status = '';
let sessionToken = '';
let error = '';

const authClient = new OktaAuthJS( {
issuer
});

authClient.signIn({
username,
password
})
.then(function(transaction) {
status = transaction.status;
sessionToken = transaction.sessionToken;
})
.catch(function(err) {
error = err;
console.error(error);
})
.finally(function() {
const qs = util.toQueryParams({
status,
sessionToken,
error
});
res.redirect('/server' + qs);
});
});

const port = config.devServer.port;
app.listen(port, function () {
console.log(`Test app running at http://localhost/${port}!\n`);
});
5 changes: 4 additions & 1 deletion test/app/src/util.js
Expand Up @@ -20,4 +20,7 @@ function toQueryParams(obj) {
}
}

export { htmlString, toQueryParams };
module.exports = {
htmlString,
toQueryParams
};
19 changes: 4 additions & 15 deletions test/app/webpack.config.js
@@ -1,19 +1,7 @@
/* global process, __dirname */
const dotenv = require('dotenv');
const fs = require('fs');
const path = require('path');
const ROOT_DIR = path.resolve(__dirname, '..', '..');

// Read environment variables from "testenv". Override environment vars if they are already set.
const TESTENV = path.resolve(ROOT_DIR, 'testenv');

if (fs.existsSync(TESTENV)) {
const envConfig = dotenv.parse(fs.readFileSync(TESTENV));
Object.keys(envConfig).forEach((k) => {
process.env[k] = envConfig[k];
});
}
require('./env'); // update environment variables from testenv file

const path = require('path');
var webpack = require('webpack');
var PORT = process.env.PORT || 8080;

Expand All @@ -22,7 +10,8 @@ module.exports = {
entry: './src/webpackEntry.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'oidc-app.js'
filename: 'oidc-app.js',
publicPath: '/'
},
plugins: [
new webpack.EnvironmentPlugin(['CLIENT_ID', 'ISSUER']),
Expand Down
53 changes: 53 additions & 0 deletions test/e2e/pageobjects/TestServer.js
@@ -0,0 +1,53 @@
import assert from 'assert';

/* eslint-disable max-len */
class TestServer {
get rootSelector() { return $('#root'); }

// form
get issuer() { return $('#issuer'); }
get username() { return $('#username'); }
get password() { return $('#password'); }
get submitBtn() { return $('#submitBtn'); }

// results
get status() { return $('#status'); }
get sessionToken() { return $('#sessionToken'); }
get error() { return $('#error'); }

async open() {
await browser.url('/server');
await browser.waitUntil(async () => this.rootSelector.then(el => el.isExisting()), 5000, 'wait for root selector');
}

async submitLogin() {
await this.submitBtn.then(el => el.click());
}

async assertLoginSuccess() {
await this.status.then(el => el.getText()).then(txt => {
assert(txt.trim() === 'SUCCESS');
});
await this.error.then(el => el.getText()).then(txt => {
assert(txt.trim() === '');
});
await this.sessionToken.then(el => el.getText()).then(txt => {
assert(txt.trim() !== '');
});
}

async assertLoginFailure() {
await this.status.then(el => el.getText()).then(txt => {
assert(txt.trim() === '');
});
await this.error.then(el => el.getText()).then(txt => {
assert(txt.trim() === 'AuthApiError: Authentication failed');
});
await this.sessionToken.then(el => el.getText()).then(txt => {
assert(txt.trim() === '');
});
}

}

export default new TestServer();
31 changes: 31 additions & 0 deletions test/e2e/specs/server.js
@@ -0,0 +1,31 @@
import TestServer from '../pageobjects/TestServer';

const ISSUER = process.env.ISSUER;
const USERNAME = process.env.USERNAME;
const PASSWORD = process.env.PASSWORD;

describe('Server-side login', () => {

beforeEach(async () => {
await TestServer.open();
});

it('can receive sessionToken with valid username/password', async () => {
await TestServer.issuer.then(el => el.setValue(ISSUER));
await TestServer.username.then(el => el.setValue(USERNAME));
await TestServer.password.then(el => el.setValue(PASSWORD));

await TestServer.submitLogin();
await TestServer.assertLoginSuccess();
});

it('will throw error for wrong password', async() => {
await TestServer.issuer.then(el => el.setValue(ISSUER));
await TestServer.username.then(el => el.setValue(USERNAME));
await TestServer.password.then(el => el.setValue('wrong password!!!'));

await TestServer.submitLogin();
await TestServer.assertLoginFailure();
});

});