Skip to content

Commit

Permalink
[E2E] Add initial draft of end-to-end testing / UI Automation (matter…
Browse files Browse the repository at this point in the history
…most#38)

* add e2e ui-automation

* update initial files
  • Loading branch information
saturninoabril committed Sep 28, 2017
1 parent d02d31b commit 2eab77c
Show file tree
Hide file tree
Showing 19 changed files with 1,059 additions and 46 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ node_modules
*.swp
.idea
*.tar.gz
tests/reports
.DS_Store
3 changes: 3 additions & 0 deletions nightwatch.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require('babel-core/register');

module.exports = require('./nightwatch.json');
85 changes: 85 additions & 0 deletions nightwatch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"src_folders": ["./tests/e2e/tests"],
"output_folder": "./tests/reports",
"custom_commands_path": "tests/e2e/commands",
"custom_assertions_path": "",
"page_objects_path": "tests/e2e/pages",
"globals_path": "tests/e2e/globals.js",
"selenium" : {
"start_process" : false,
"server_path" : "",
"log_path" : "",
"host" : "localhost",
"port" : 4444,
"cli_args" : {
"webdriver.chrome.driver" : "",
"webdriver.ie.driver" : "",
"webdriver.gecko.driver": ""
}
},
"test_settings": {
"default": {
"launch_url": "http:https://localhost:8065/",
"selenium_port": 4444,
"selenium_host": "localhost",
"silent": true,
"skip_testcases_on_fail": false,
"end_session_on_fail": false,
"resolution": "1920x1080",
"exclude": "utils.js",
"screenshots": {
"enabled": true,
"on_failure": true,
"path": "./tests/reports/screenshots"
},
"desiredCapabilities": {
"browserName": "firefox",
"unexpectedAlertBehaviour": "dismiss",
"javascriptEnabled": true,
"acceptSslCerts": true,
"elementScrollBehavior": "1"
}
},
"chrome": {
"desiredCapabilities": {
"browserName": "chrome",
"javascriptEnabled": true,
"acceptSslCerts": true,
"chromeOptions": {
"args": ["window-position=0,0", "window-size=1920,1080", "--disable-popup-blocking"]
}
}
},
"firefox": {
"desiredCapabilities": {
"browserName": "firefox",
"unexpectedAlertBehaviour": "dismiss",
"javascriptEnabled": true,
"acceptSslCerts": true,
"elementScrollBehavior": "1"
}
},
"360x640": {
"resolution": "360x640",
"desiredCapabilities": {
"browserName": "chrome",
"javascriptEnabled": true,
"acceptSslCerts": true,
"chromeOptions": {
"args": ["window-position=0,0", "window-size=360,640"]
}
}
},
"768x1024": {
"resolution": "768x1024",
"desiredCapabilities": {
"browserName": "chrome",
"javascriptEnabled": true,
"acceptSslCerts": true,
"chromeOptions": {
"args": ["window-position=0,0", "window-size=768,1024"]
}
}
}
}
}
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,14 @@
"jsdom": "11.1.0",
"jsdom-global": "3.0.2",
"json-loader": "0.5.7",
"nightwatch": "0.9.16",
"node-sass": "4.5.3",
"raw-loader": "0.5.1",
"react-addons-test-utils": "15.6.0",
"remote-redux-devtools": "0.5.12",
"remote-redux-devtools-on-debugger": "0.8.2",
"sass-loader": "6.0.6",
"selenium-standalone": "6.6.0",
"style-loader": "0.18.2",
"url-loader": "0.5.9",
"webpack": "3.5.5",
Expand Down Expand Up @@ -136,6 +138,12 @@
"test": "jest",
"updatesnapshot": "jest --updateSnapshot",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
"test:coverage": "jest --coverage",
"e2e": "./tests/e2e/test.sh",
"e2e-local-chrome": "nightwatch -e chrome --suiteRetries 1",
"e2e-local-firefox": "nightwatch -e firefox --suiteRetries 1",
"e2e-tag": "nightwatch -e chrome --suiteRetries 1 --tag",
"selenium-install": "selenium-standalone install --config=./tests/e2e/config.js",
"selenium-start": "selenium-standalone start --config=./tests/e2e/config.js"
}
}
11 changes: 11 additions & 0 deletions tests/e2e/commands/fillInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

exports.command = function fillInput(element, string) {
return this
.waitForElementVisible(element, 3000)
.clearValue(element)
.pause(300)
.setValue(element, string)
.pause(1000);
};
10 changes: 10 additions & 0 deletions tests/e2e/commands/getChromeLogs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

exports.command = function getChromeLogs() {
return this.getLog('browser', (logEntriesArray) => {
logEntriesArray.forEach((log) => {
console.log(`[${log.level}] Timestamp: ${log.timestamp}\n`); //eslint-disable-line no-console
});
});
};
27 changes: 27 additions & 0 deletions tests/e2e/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

module.exports = {
baseURL: "https://selenium-release.storage.googleapis.com",
version: "3.4.0",
drivers: {
chrome: {
version: "2.31",
arch: process.arch,
baseURL: "https://chromedriver.storage.googleapis.com"
},
ie: {
version: '3.4.0',
arch: process.arch,
baseURL: 'https://selenium-release.storage.googleapis.com'
},
firefox: {
version: '0.17.0',
arch: process.arch,
baseURL: 'https://github.com/mozilla/geckodriver/releases/download'
},
edge: {
version: '15063'
}
}
};
55 changes: 55 additions & 0 deletions tests/e2e/globals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

module.exports = {
// this controls whether to abort the test execution when an assertion failed and skip the rest
// it's being used in waitFor commands and expect assertions
abortOnAssertionFailure: true,

// this will overwrite the default polling interval (currently 500ms) for waitFor commands
// and expect assertions that use retry
waitForConditionPollInterval: 300,

// default timeout value in milliseconds for waitFor commands and implicit waitFor value for
// expect assertions
waitForConditionTimeout: 5000,

// this will cause waitFor commands on elements to throw an error if multiple
// elements are found using the given locate strategy and selector
throwOnMultipleElementsReturned: true,

// controls the timeout time for async hooks. Expects the done() callback to be invoked within this time
// or an error is thrown
asyncHookTimeout: 10000,

default: {
myGlobal: function() {
return "";
}
},

test_env: {
myGlobal: 'test_global',
beforeEach: function() {}
},

before: function(cb) {
cb();
},

beforeEach: function(browser, cb) {
cb();
},

after: function(cb) {
cb();
},

afterEach: function(browser, cb) {
cb();
},

reporter: function(results, cb) {
cb();
}
};
73 changes: 73 additions & 0 deletions tests/e2e/pages/centerChannelHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {Constants} from '../utils';

const centerChannelHeaderCommands = {
navigateToPage() {
return this.waitForElementVisible('@headerContainer', Constants.DEFAULT_WAIT);
}
};

module.exports = {
url: `${Constants.TEST_BASE_URL}`,
commands: [centerChannelHeaderCommands],
elements: {
headerContainer: {
selector: '//*[@id="channel-header"]',
locateStrategy: 'xpath'
},
flexParent: {
selector: '//*[@id="channel-header"]/div',
locateStrategy: 'xpath'
},
headerInfo: {
selector: '//*[@id="channel-header"]/div/div[1]/div',
locateStrategy: 'xpath'
},
toggleFavorite: {
selector: '//*[@id="toggleFavorite"]',
locateStrategy: 'xpath'
},
dropdownButton: {
selector: '//*[@id="channelHeaderDropdown"]',
locateStrategy: 'xpath'
},
dropdownMenu: {
selector: '//*[@id="channel-header"]/div/div[1]/div/div/ul',
locateStrategy: 'xpath'
},
headerDescription: {
selector: '//*[@id="channel-header"]/div/div[1]/div/a[2]',
locateStrategy: 'xpath'
},
headerMember: {
selector: '//*[@id="channel-header"]/div/div[3]/div',
locateStrategy: 'xpath'
},
headerMemberText: {
selector: '//*[@id="member_popover"]/span[1]',
locateStrategy: 'xpath'
},
headerMemberIcon: {
selector: '//*[@id="member_popover"]/span[2]',
locateStrategy: 'xpath'
},
headerPin: {
selector: '//*[@id="channel-header"]/div/div[4]/div',
locateStrategy: 'xpath'
},
headerSearchBar: {
selector: '//*[@id="channel-header"]/div/div[5]',
locateStrategy: 'xpath'
},
headerAtMention: {
selector: '//*[@id="channel-header"]/div/div[6]/div',
locateStrategy: 'xpath'
},
headerFlag: {
selector: '//*[@id="channel-header"]/div/div[7]/div',
locateStrategy: 'xpath'
}
}
};
48 changes: 48 additions & 0 deletions tests/e2e/pages/centerPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {Constants} from '../utils';

const centerCommands = {
navigateToPage() {
return this.waitForElementVisible('@postTextBox', Constants.DEFAULT_WAIT);
},
postAMessage(message) {
return this
.waitForElementVisible('@postTextBox', Constants.DEFAULT_WAIT)
.setValue('@postTextBox', message)
.keys(this.Keys.ENTER)
.waitForElementVisible('@postListContent', Constants.DEFAULT_WAIT);
}
};

module.exports = {
url: `${Constants.TEST_BASE_URL}`,
commands: [centerCommands],
elements: {
postTextBox: {
selector: '//*[@id="post_textbox"]',
locateStrategy: 'xpath'
},
fileAttachmentButton: {
selector: '//*[@id="create_post"]/div/div[1]/div/span/span[1]/div',
locateStrategy: 'xpath'
},
emojiPickerButton: {
selector: '//*[@id="create_post"]/div/div[1]/div/span/span[2]/span',
locateStrategy: 'xpath'
},
helpLink: {
selector: '//*[@id="create_post"]/div/div[1]/div/div/div[3]/a',
locateStrategy: 'xpath'
},
helpText: {
selector: '//*[@id="create_post"]/div/div[1]/div/div/div[3]/div',
locateStrategy: 'xpath'
},
postListContent: {
selector: '//*[@id="post-list"]/div[2]/div/div',
locateStrategy: 'xpath'
}
}
};
39 changes: 39 additions & 0 deletions tests/e2e/pages/loginPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {Constants} from '../utils';

const loginCommands = {
navigateToPage() {
return this.waitForElementVisible('@loginInput', Constants.DEFAULT_WAIT);
},
login(email, pass) {
return this
.waitForElementVisible('@loginInput', Constants.DEFAULT_WAIT)
.setValue('@loginInput', email)
.setValue('@passwordInput', pass)
.waitForElementVisible('@signinButton', Constants.DEFAULT_WAIT)
.click('@signinButton')
.waitForElementVisible('@postTextBox', Constants.DEFAULT_WAIT);
}
};

module.exports = {
url: `${Constants.TEST_BASE_URL}/login`,
commands: [loginCommands],
elements: {
loginInput: {
selector: 'input[name=loginId]'
},
passwordInput: {
selector: 'input[name=password]'
},
signinButton: {
selector: 'button[type=submit]'
},
postTextBox: {
selector: '//*[@id="post_textbox"]',
locateStrategy: 'xpath'
}
}
};
Loading

0 comments on commit 2eab77c

Please sign in to comment.