Merge pull request #142 from clems4ever/test-forward-headers
Add test for headers forwarding featurepull/144/head
commit
cb139997d2
|
@ -0,0 +1,6 @@
|
||||||
|
version: '2'
|
||||||
|
services:
|
||||||
|
httpbin:
|
||||||
|
image: citizenstig/httpbin
|
||||||
|
networks:
|
||||||
|
- example-network
|
|
@ -74,6 +74,7 @@ http {
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
proxy_pass http://authelia/verify;
|
proxy_pass http://authelia/verify;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +83,6 @@ http {
|
||||||
auth_request /auth_verify;
|
auth_request /auth_verify;
|
||||||
|
|
||||||
auth_request_set $redirect $upstream_http_redirect;
|
auth_request_set $redirect $upstream_http_redirect;
|
||||||
proxy_set_header Redirect $redirect;
|
|
||||||
|
|
||||||
auth_request_set $user $upstream_http_remote_user;
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
proxy_set_header X-Forwarded-User $user;
|
proxy_set_header X-Forwarded-User $user;
|
||||||
|
@ -93,6 +93,23 @@ http {
|
||||||
error_page 401 =302 https://auth.test.local:8080?redirect=$redirect;
|
error_page 401 =302 https://auth.test.local:8080?redirect=$redirect;
|
||||||
error_page 403 = https://auth.test.local:8080/error/403;
|
error_page 403 = https://auth.test.local:8080/error/403;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /headers {
|
||||||
|
auth_request /auth_verify;
|
||||||
|
|
||||||
|
auth_request_set $redirect $upstream_http_redirect;
|
||||||
|
|
||||||
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
|
proxy_set_header Custom-Forwarded-User $user;
|
||||||
|
|
||||||
|
auth_request_set $groups $upstream_http_remote_groups;
|
||||||
|
proxy_set_header Custom-Forwarded-Groups $groups;
|
||||||
|
|
||||||
|
proxy_pass http://httpbin:8000/headers;
|
||||||
|
|
||||||
|
error_page 401 =302 https://auth.test.local:8080?redirect=$redirect;
|
||||||
|
error_page 403 = https://auth.test.local:8080/error/403;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
|
@ -110,6 +127,7 @@ http {
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
proxy_pass http://authelia/verify;
|
proxy_pass http://authelia/verify;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +136,6 @@ http {
|
||||||
auth_request /auth_verify;
|
auth_request /auth_verify;
|
||||||
|
|
||||||
auth_request_set $redirect $upstream_http_redirect;
|
auth_request_set $redirect $upstream_http_redirect;
|
||||||
proxy_set_header Redirect $redirect;
|
|
||||||
|
|
||||||
auth_request_set $user $upstream_http_remote_user;
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
proxy_set_header X-Forwarded-User $user;
|
proxy_set_header X-Forwarded-User $user;
|
||||||
|
@ -146,6 +163,7 @@ http {
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
proxy_pass http://authelia/verify;
|
proxy_pass http://authelia/verify;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +172,6 @@ http {
|
||||||
auth_request /auth_verify;
|
auth_request /auth_verify;
|
||||||
|
|
||||||
auth_request_set $redirect $upstream_http_redirect;
|
auth_request_set $redirect $upstream_http_redirect;
|
||||||
proxy_set_header Redirect $redirect;
|
|
||||||
|
|
||||||
auth_request_set $user $upstream_http_remote_user;
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
proxy_set_header X-Forwarded-User $user;
|
proxy_set_header X-Forwarded-User $user;
|
||||||
|
@ -191,7 +208,6 @@ http {
|
||||||
auth_request /auth_verify;
|
auth_request /auth_verify;
|
||||||
|
|
||||||
auth_request_set $redirect $upstream_http_redirect;
|
auth_request_set $redirect $upstream_http_redirect;
|
||||||
proxy_set_header Redirect $redirect;
|
|
||||||
|
|
||||||
auth_request_set $user $upstream_http_remote_user;
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
proxy_set_header X-Forwarded-User $user;
|
proxy_set_header X-Forwarded-User $user;
|
||||||
|
@ -228,7 +244,6 @@ http {
|
||||||
auth_request /auth_verify;
|
auth_request /auth_verify;
|
||||||
|
|
||||||
auth_request_set $redirect $upstream_http_redirect;
|
auth_request_set $redirect $upstream_http_redirect;
|
||||||
proxy_set_header Redirect $redirect;
|
|
||||||
|
|
||||||
auth_request_set $user $upstream_http_remote_user;
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
proxy_set_header X-Forwarded-User $user;
|
proxy_set_header X-Forwarded-User $user;
|
||||||
|
|
|
@ -71,7 +71,6 @@
|
||||||
"@types/request-promise": "^4.1.38",
|
"@types/request-promise": "^4.1.38",
|
||||||
"@types/selenium-webdriver": "^3.0.4",
|
"@types/selenium-webdriver": "^3.0.4",
|
||||||
"@types/sinon": "^2.2.1",
|
"@types/sinon": "^2.2.1",
|
||||||
"@types/speakeasy": "^2.0.1",
|
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"@types/winston": "^2.3.2",
|
"@types/winston": "^2.3.2",
|
||||||
"@types/yamljs": "^0.2.30",
|
"@types/yamljs": "^0.2.30",
|
||||||
|
|
|
@ -10,5 +10,6 @@ docker-compose \
|
||||||
-f example/redis/docker-compose.yml \
|
-f example/redis/docker-compose.yml \
|
||||||
-f example/nginx/docker-compose.yml \
|
-f example/nginx/docker-compose.yml \
|
||||||
-f example/smtp/docker-compose.yml \
|
-f example/smtp/docker-compose.yml \
|
||||||
|
-f example/httpbin/docker-compose.yml \
|
||||||
-f example/ldap/docker-compose.admin.yml \
|
-f example/ldap/docker-compose.admin.yml \
|
||||||
-f example/ldap/docker-compose.yml $*
|
-f example/ldap/docker-compose.yml $*
|
||||||
|
|
|
@ -9,4 +9,5 @@ docker-compose \
|
||||||
-f example/redis/docker-compose.yml \
|
-f example/redis/docker-compose.yml \
|
||||||
-f example/nginx/docker-compose.yml \
|
-f example/nginx/docker-compose.yml \
|
||||||
-f example/smtp/docker-compose.yml \
|
-f example/smtp/docker-compose.yml \
|
||||||
|
-f example/httpbin/docker-compose.yml \
|
||||||
-f example/ldap/docker-compose.yml $*
|
-f example/ldap/docker-compose.yml $*
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
DC_SCRIPT=./scripts/example-commit/dc-example.sh
|
DC_SCRIPT=./scripts/example-commit/dc-example.sh
|
||||||
|
|
||||||
$DC_SCRIPT build
|
$DC_SCRIPT build
|
||||||
$DC_SCRIPT up -d mongo redis openldap authelia nginx smtp
|
$DC_SCRIPT up -d httpbin mongo redis openldap authelia nginx smtp
|
||||||
|
|
|
@ -9,4 +9,5 @@ docker-compose \
|
||||||
-f example/redis/docker-compose.yml \
|
-f example/redis/docker-compose.yml \
|
||||||
-f example/nginx/docker-compose.yml \
|
-f example/nginx/docker-compose.yml \
|
||||||
-f example/smtp/docker-compose.yml \
|
-f example/smtp/docker-compose.yml \
|
||||||
|
-f example/httpbin/docker-compose.yml \
|
||||||
-f example/ldap/docker-compose.yml $*
|
-f example/ldap/docker-compose.yml $*
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
DC_SCRIPT=./scripts/example-dockerhub/dc-example.sh
|
DC_SCRIPT=./scripts/example-dockerhub/dc-example.sh
|
||||||
|
|
||||||
#$DC_SCRIPT build
|
#$DC_SCRIPT build
|
||||||
$DC_SCRIPT up -d mongo redis openldap authelia nginx smtp
|
$DC_SCRIPT up -d httpbin mongo redis openldap authelia nginx smtp
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
DC_SCRIPT=./scripts/example-commit/dc-example.sh
|
DC_SCRIPT=./scripts/example-commit/dc-example.sh
|
||||||
EXPECTED_SERVICES_COUNT=6
|
EXPECTED_SERVICES_COUNT=7
|
||||||
|
|
||||||
build_services() {
|
build_services() {
|
||||||
$DC_SCRIPT build authelia
|
$DC_SCRIPT build authelia
|
||||||
}
|
}
|
||||||
|
|
||||||
start_services() {
|
start_services() {
|
||||||
$DC_SCRIPT up -d mongo redis openldap authelia nginx smtp
|
$DC_SCRIPT up -d httpbin mongo redis openldap authelia nginx smtp
|
||||||
sleep 3
|
sleep 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
|
|
||||||
import * as speakeasy from "speakeasy";
|
import Speakeasy = require("speakeasy");
|
||||||
import { Speakeasy } from "../../types/Dependencies";
|
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
import { TOTPSecret } from "../../types/TOTPSecret";
|
||||||
|
|
||||||
|
interface GenerateSecretOptions {
|
||||||
|
length?: number;
|
||||||
|
symbols?: boolean;
|
||||||
|
otpauth_url?: boolean;
|
||||||
|
name?: string;
|
||||||
|
issuer?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class TOTPGenerator {
|
export class TOTPGenerator {
|
||||||
private speakeasy: Speakeasy;
|
private speakeasy: typeof Speakeasy;
|
||||||
|
|
||||||
constructor(speakeasy: Speakeasy) {
|
constructor(speakeasy: typeof Speakeasy) {
|
||||||
this.speakeasy = speakeasy;
|
this.speakeasy = speakeasy;
|
||||||
}
|
}
|
||||||
|
|
||||||
generate(options?: speakeasy.GenerateOptions): speakeasy.Key {
|
generate(options?: GenerateSecretOptions): TOTPSecret {
|
||||||
return this.speakeasy.generateSecret(options);
|
return this.speakeasy.generateSecret(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,23 +1,27 @@
|
||||||
|
import Speakeasy = require("speakeasy");
|
||||||
import { Speakeasy } from "../../types/Dependencies";
|
|
||||||
import BluebirdPromise = require("bluebird");
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
const TOTP_ENCODING = "base32";
|
const TOTP_ENCODING = "base32";
|
||||||
|
const WINDOW: number = 1;
|
||||||
|
|
||||||
export class TOTPValidator {
|
export class TOTPValidator {
|
||||||
private speakeasy: Speakeasy;
|
private speakeasy: typeof Speakeasy;
|
||||||
|
|
||||||
constructor(speakeasy: Speakeasy) {
|
constructor(speakeasy: typeof Speakeasy) {
|
||||||
this.speakeasy = speakeasy;
|
this.speakeasy = speakeasy;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(token: string, secret: string): BluebirdPromise<void> {
|
validate(token: string, secret: string): BluebirdPromise<void> {
|
||||||
const real_token = this.speakeasy.totp({
|
const isValid = this.speakeasy.totp.verify({
|
||||||
secret: secret,
|
secret: secret,
|
||||||
encoding: TOTP_ENCODING
|
encoding: TOTP_ENCODING,
|
||||||
});
|
token: token,
|
||||||
|
window: WINDOW
|
||||||
|
} as any);
|
||||||
|
|
||||||
if (token == real_token) return BluebirdPromise.resolve();
|
if (isValid)
|
||||||
return BluebirdPromise.reject(new Error("Wrong challenge"));
|
return BluebirdPromise.resolve();
|
||||||
|
else
|
||||||
|
return BluebirdPromise.reject(new Error("Wrong TOTP token."));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,26 +1,37 @@
|
||||||
|
|
||||||
import { TOTPValidator } from "../src/lib/TOTPValidator";
|
import { TOTPValidator } from "../src/lib/TOTPValidator";
|
||||||
import sinon = require("sinon");
|
import Sinon = require("sinon");
|
||||||
import Promise = require("bluebird");
|
import Speakeasy = require("speakeasy");
|
||||||
import SpeakeasyMock = require("./mocks/speakeasy");
|
|
||||||
|
|
||||||
describe("test TOTP validation", function() {
|
describe("test TOTP validation", function() {
|
||||||
let totpValidator: TOTPValidator;
|
let totpValidator: TOTPValidator;
|
||||||
|
let totpValidateStub: Sinon.SinonStub;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
SpeakeasyMock.totp.returns("token");
|
totpValidateStub = Sinon.stub(Speakeasy.totp, "verify");
|
||||||
totpValidator = new TOTPValidator(SpeakeasyMock as any);
|
totpValidator = new TOTPValidator(Speakeasy);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
totpValidateStub.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should validate the TOTP token", function() {
|
it("should validate the TOTP token", function() {
|
||||||
const totp_secret = "NBD2ZV64R9UV1O7K";
|
const totp_secret = "NBD2ZV64R9UV1O7K";
|
||||||
const token = "token";
|
const token = "token";
|
||||||
|
totpValidateStub.withArgs({
|
||||||
|
secret: totp_secret,
|
||||||
|
token: token,
|
||||||
|
encoding: "base32",
|
||||||
|
window: 1
|
||||||
|
}).returns(true);
|
||||||
return totpValidator.validate(token, totp_secret);
|
return totpValidator.validate(token, totp_secret);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not validate a wrong TOTP token", function(done) {
|
it("should not validate a wrong TOTP token", function(done) {
|
||||||
const totp_secret = "NBD2ZV64R9UV1O7K";
|
const totp_secret = "NBD2ZV64R9UV1O7K";
|
||||||
const token = "wrong token";
|
const token = "wrong token";
|
||||||
|
totpValidateStub.returns(false);
|
||||||
totpValidator.validate(token, totp_secret)
|
totpValidator.validate(token, totp_secret)
|
||||||
.catch(function() {
|
.catch(function() {
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -29,7 +29,12 @@ describe("test user data store", function () {
|
||||||
totpSecret = {
|
totpSecret = {
|
||||||
ascii: "abc",
|
ascii: "abc",
|
||||||
base32: "ABCDKZLEFZGREJK",
|
base32: "ABCDKZLEFZGREJK",
|
||||||
otpauth_url: "totp://test"
|
otpauth_url: "totp://test",
|
||||||
|
google_auth_qr: "dummy",
|
||||||
|
hex: "dummy",
|
||||||
|
qr_code_ascii: "dummy",
|
||||||
|
qr_code_base32: "dummy",
|
||||||
|
qr_code_hex: "dummy"
|
||||||
};
|
};
|
||||||
|
|
||||||
u2fRegistration = {
|
u2fRegistration = {
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
|
||||||
export interface TOTPSecret {
|
export interface TOTPSecret {
|
||||||
base32: string;
|
|
||||||
ascii: string;
|
ascii: string;
|
||||||
otpauth_url?: string;
|
hex: string;
|
||||||
}
|
base32: string;
|
||||||
|
qr_code_ascii: string;
|
||||||
|
qr_code_hex: string;
|
||||||
|
qr_code_base32: string;
|
||||||
|
google_auth_qr: string;
|
||||||
|
otpauth_url: string;
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
declare module "speakeasy" {
|
||||||
|
export = speakeasy
|
||||||
|
|
||||||
|
interface SharedOptions {
|
||||||
|
encoding?: string
|
||||||
|
algorithm?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DigestOptions extends SharedOptions {
|
||||||
|
secret: string
|
||||||
|
counter: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HOTPOptions extends SharedOptions {
|
||||||
|
secret: string
|
||||||
|
counter: number
|
||||||
|
digest?: Buffer
|
||||||
|
digits?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HOTPVerifyOptions extends SharedOptions {
|
||||||
|
secret: string
|
||||||
|
token: string
|
||||||
|
counter: number
|
||||||
|
digits?: number
|
||||||
|
window?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TOTPOptions extends SharedOptions {
|
||||||
|
secret: string
|
||||||
|
time?: number
|
||||||
|
step?: number
|
||||||
|
epoch?: number
|
||||||
|
counter?: number
|
||||||
|
digits?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TOTPVerifyOptions extends SharedOptions {
|
||||||
|
secret: string
|
||||||
|
token: string
|
||||||
|
time?: number
|
||||||
|
step?: number
|
||||||
|
epoch?: number
|
||||||
|
counter?: number
|
||||||
|
digits?: number
|
||||||
|
window?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GenerateSecretOptions {
|
||||||
|
length?: number
|
||||||
|
symbols?: boolean
|
||||||
|
otpauth_url?: boolean
|
||||||
|
name?: string
|
||||||
|
issuer?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneratedSecret {
|
||||||
|
ascii: string
|
||||||
|
hex: string
|
||||||
|
base32: string
|
||||||
|
qr_code_ascii: string
|
||||||
|
qr_code_hex: string
|
||||||
|
qr_code_base32: string
|
||||||
|
google_auth_qr: string
|
||||||
|
otpauth_url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OTPAuthURLOptions extends SharedOptions {
|
||||||
|
secret: string
|
||||||
|
label: string
|
||||||
|
type?: string
|
||||||
|
counter?: number
|
||||||
|
issuer?: string
|
||||||
|
digits?: number
|
||||||
|
period?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Speakeasy {
|
||||||
|
digest: (options: DigestOptions) => Buffer
|
||||||
|
hotp: {
|
||||||
|
(options: HOTPOptions): string,
|
||||||
|
verifyDelta: (options: HOTPVerifyOptions) => boolean,
|
||||||
|
verify: (options: HOTPVerifyOptions) => boolean,
|
||||||
|
}
|
||||||
|
totp: {
|
||||||
|
(options: TOTPOptions): string
|
||||||
|
verifyDelta: (options: TOTPVerifyOptions) => boolean,
|
||||||
|
verify: (options: TOTPVerifyOptions) => boolean,
|
||||||
|
}
|
||||||
|
generateSecret: (options?: GenerateSecretOptions) => GeneratedSecret
|
||||||
|
generateSecretASCII: (length?: number, symbols?: boolean) => string
|
||||||
|
otpauthURL: (options: OTPAuthURLOptions) => string
|
||||||
|
}
|
||||||
|
|
||||||
|
const speakeasy: Speakeasy
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
Feature: User and groups headers are correctly forwarded to backend
|
||||||
|
@need-authenticated-user-john
|
||||||
|
Scenario: Custom-Forwarded-User and Custom-Forwarded-Groups are correctly forwarded to protected backend
|
||||||
|
When I visit "https://public.test.local:8080/headers"
|
||||||
|
Then I see header "Custom-Forwarded-User" set to "john"
|
||||||
|
Then I see header "Custom-Forwarded-Groups" set to "dev,admin"
|
|
@ -0,0 +1,20 @@
|
||||||
|
import Cucumber = require("cucumber");
|
||||||
|
import seleniumWebdriver = require("selenium-webdriver");
|
||||||
|
import CustomWorld = require("../support/world");
|
||||||
|
import Util = require("util");
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
|
||||||
|
Cucumber.defineSupportCode(function ({ Given, When, Then }) {
|
||||||
|
Then("I see header {stringInDoubleQuotes} set to {stringInDoubleQuotes}",
|
||||||
|
{ timeout: 5000 },
|
||||||
|
function (expectedHeaderName: string, expectedValue: string) {
|
||||||
|
return this.driver.findElement(seleniumWebdriver.By.tagName("body")).getText()
|
||||||
|
.then(function (txt: string) {
|
||||||
|
const expectedLine = Util.format("\"%s\": \"%s\"", expectedHeaderName, expectedValue);
|
||||||
|
if (txt.indexOf(expectedLine) > 0)
|
||||||
|
return BluebirdPromise.resolve();
|
||||||
|
else
|
||||||
|
return BluebirdPromise.reject(new Error(Util.format("No such header or with unexpected value.")));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
|
@ -23,5 +23,4 @@ Cucumber.defineSupportCode(function ({ Given, When, Then }) {
|
||||||
return that.driver.sleep(500);
|
return that.driver.sleep(500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
|
@ -21,6 +21,7 @@ function CustomWorld() {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setFieldTo = function (fieldName: string, content: string) {
|
this.setFieldTo = function (fieldName: string, content: string) {
|
||||||
|
const that = this;
|
||||||
return this.driver.findElement(seleniumWebdriver.By.id(fieldName))
|
return this.driver.findElement(seleniumWebdriver.By.id(fieldName))
|
||||||
.sendKeys(content);
|
.sendKeys(content);
|
||||||
};
|
};
|
||||||
|
@ -49,14 +50,19 @@ function CustomWorld() {
|
||||||
.findElement(seleniumWebdriver.By.tagName("button"))
|
.findElement(seleniumWebdriver.By.tagName("button"))
|
||||||
.findElement(seleniumWebdriver.By.xpath("//button[contains(.,'" + buttonText + "')]"))
|
.findElement(seleniumWebdriver.By.xpath("//button[contains(.,'" + buttonText + "')]"))
|
||||||
.click();
|
.click();
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
return that.driver.sleep(1000);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.waitUntilUrlContains = function(url: string) {
|
this.waitUntilUrlContains = function (url: string) {
|
||||||
return this.driver.wait(seleniumWebdriver.until.urlIs(url), 15000);
|
const that = this;
|
||||||
|
return this.driver.wait(seleniumWebdriver.until.urlIs(url), 15000)
|
||||||
|
.then(function () { }, function (err: Error) {
|
||||||
|
that.driver.getCurrentUrl()
|
||||||
|
.then(function (current: string) {
|
||||||
|
console.error("====> Error due to: %s (current) != %s (expected)", current, url);
|
||||||
|
});
|
||||||
|
return BluebirdPromise.reject(err);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.loginWithUserPassword = function (username: string, password: string) {
|
this.loginWithUserPassword = function (username: string, password: string) {
|
||||||
|
|
Loading…
Reference in New Issue