Add ui tests infrastructure and tests for language setting

This commit is contained in:
Dipak Acharya
2020-08-04 13:30:40 +05:45
parent 0cc0f5bf26
commit 6512403a2f
14 changed files with 2312 additions and 368 deletions

View File

@@ -1,6 +1,7 @@
def main(ctx):
before = [
testing(ctx),
UITests(ctx, 'master', '0c6478c9350f56ff6d7c402b5d9d60a68b0f6f75', 'master', '2e1af4c27f21439ead1e3358f9690e9ffa7eb75a')
]
stages = [
@@ -699,3 +700,162 @@ def website(ctx):
],
},
}
def UITests(ctx, ocisBranch, ocisCommitId, phoenixBranch, phoenixCommitId):
return {
'kind': 'pipeline',
'type': 'docker',
'name': 'UiTests',
'platform': {
'os': 'linux',
'arch': 'amd64',
},
'steps': [
{
'name': 'build',
'image': 'webhippie/golang:1.13',
'pull': 'always',
'commands': [
'make protobuf build',
],
'volumes': [
{
'name': 'gopath',
'path': '/srv/app',
},
],
},
{
'name': 'build-ocis',
'image': 'webhippie/golang:1.13',
'pull': 'always',
'commands': [
'git clone -b %s --single-branch --no-tags https://github.com/owncloud/ocis /srv/app/ocis' % (ocisBranch),
'cd /srv/app/ocis',
'git checkout %s' % (ocisCommitId),
'make build',
],
'volumes': [
{
'name': 'gopath',
'path': '/srv/app'
},
]
},
{
'name': 'ocis-server',
'image': 'webhippie/golang:1.13',
'pull': 'always',
'detach': True,
'environment' : {
'OCIS_LOG_LEVEL': 'debug',
'REVA_STORAGE_HOME_DATA_TEMP_FOLDER': '/srv/app/tmp/',
'REVA_STORAGE_LOCAL_ROOT': '/srv/app/tmp/reva/root',
'REVA_STORAGE_OWNCLOUD_DATADIR': '/srv/app/tmp/reva/data',
'REVA_STORAGE_OC_DATA_TEMP_FOLDER': '/srv/app/tmp/',
'REVA_STORAGE_OWNCLOUD_REDIS_ADDR': 'redis:6379',
'REVA_LDAP_IDP': 'https://ocis-server:9200',
'REVA_OIDC_ISSUER': 'https://ocis-server:9200',
'PROXY_OIDC_ISSUER': 'https://ocis-server:9200',
'REVA_STORAGE_OC_DATA_SERVER_URL': 'http://ocis-server:9164/data',
'REVA_DATAGATEWAY_URL': 'https://ocis-server:9200/data',
'REVA_FRONTEND_URL': 'https://ocis-server:9200',
'PHOENIX_WEB_CONFIG': '/drone/src/ui/tests/config/drone/ocis-config.json',
'KONNECTD_IDENTIFIER_REGISTRATION_CONF': '/drone/src/ui/tests/config/drone/identifier-registration.yml',
'KONNECTD_ISS': 'https://ocis-server:9200',
'KONNECTD_TLS': 'true',
'OCIS_CONFIG_FILE': '/drone/src/ui/tests/config/drone/proxy-config.json',
'SETTINGS_DATA_PATH': '/srv/app/settings-store'
},
'commands': [
'mkdir -p /srv/app/tmp/reva',
# Start ocis settings first
'bin/ocis-settings server &',
# Now run all the ocis services except the settings because it is already running
'/srv/app/ocis/bin/ocis server',
],
'volumes': [
{
'name': 'gopath',
'path': '/srv/app'
},
]
},
{
'name': 'WebUIAcceptanceTests',
'image': 'owncloudci/nodejs:10',
'pull': 'always',
'environment': {
'SERVER_HOST': 'https://ocis-server:9200',
'BACKEND_HOST': 'https://ocis-server:9200',
'RUN_ON_OCIS': 'true',
'OCIS_REVA_DATA_ROOT': '/srv/app/tmp/reva',
'OCIS_SKELETON_DIR': '/srv/app/testing/data/webUISkeleton',
'PHOENIX_CONFIG': '/drone/src/ui/tests/config/drone/ocis-config.json',
'TEST_TAGS': 'not @skipOnOCIS and not @skip',
'LOCAL_UPLOAD_DIR': '/uploads',
'PHOENIX_PATH': '/srv/app/phoenix',
'FEATURE_PATH': 'ui/tests/acceptance/features',
'NODE_TLS_REJECT_UNAUTHORIZED': '0',
'OCIS_SETTINGS_STORE': '/srv/app/settings-store'
},
'commands': [
'git clone --depth=1 https://github.com/owncloud/testing.git /srv/app/testing',
'git clone -b %s --single-branch https://github.com/owncloud/phoenix /srv/app/phoenix' % (phoenixBranch),
'cd /srv/app/phoenix',
'git checkout %s' % (phoenixCommitId),
'cp -r /srv/app/phoenix/tests/acceptance/filesForUpload/* /uploads',
'yarn install-all',
'yarn dist',
'cp -r /drone/src/ui/tests/config/drone/ocis-config.json /srv/app/phoenix/dist/config.json',
'cd /drone/src',
'yarn install --all',
'make test-acceptance-webui',
],
'volumes': [{
'name': 'gopath',
'path': '/srv/app',
},
{
'name': 'uploads',
'path': '/uploads'
}]
},
],
'services': [
{
'name': 'redis',
'image': 'webhippie/redis',
'pull': 'always',
'environment': {
'REDIS_DATABASES': 1
},
},
{
'name': 'selenium',
'image': 'selenium/standalone-chrome-debug:3.141.59-20200326',
'pull': 'always',
'volumes': [{
'name': 'uploads',
'path': '/uploads'
}],
},
],
'volumes': [
{
'name': 'gopath',
'temp': {},
},
{
'name': 'uploads',
'temp': {}
}
],
'trigger': {
'ref': [
'refs/heads/master',
'refs/tags/**',
'refs/pull/**',
],
},
}

View File

@@ -24,6 +24,7 @@ endif
PACKAGES ?= $(shell go list ./...)
SOURCES ?= $(shell find . -name "*.go" -type f -not -path "./node_modules/*")
GENERATE ?= $(PACKAGES)
FEATURE_PATH ?= "ui/tests/acceptance/features"
TAGS ?=
@@ -134,6 +135,10 @@ release-check:
.PHONY: release-finish
release-finish: release-copy release-check
.PHONY: test-acceptance-webui
test-acceptance-webui:
./ui/tests/run-acceptance-test.sh $(FEATURE_PATH)
.PHONY: docs-copy
docs-copy:
mkdir -p $(HUGO); \

15
nightwatch.conf.js Normal file
View File

@@ -0,0 +1,15 @@
const path = require('path')
const PHOENIX_PATH = process.env.PHOENIX_PATH
const TEST_INFRA_DIRECTORY = process.env.TEST_INFRA_DIRECTORY
const OCIS_SETTINGS_STORE = process.env.OCIS_SETTINGS_STORE || './ocis-settings-store'
const config = require(path.join(PHOENIX_PATH, 'nightwatch.conf.js'))
config.page_objects_path = [TEST_INFRA_DIRECTORY + '/acceptance/pageObjects', 'ui/tests/acceptance/pageobjects']
config.custom_commands_path = TEST_INFRA_DIRECTORY + '/acceptance/customCommands'
config.test_settings.default.globals = { ...config.test_settings.default.globals, settings_store: OCIS_SETTINGS_STORE }
module.exports = {
...config
}

View File

@@ -16,10 +16,13 @@
"build": "rollup -c",
"watch": "rollup -c -w",
"test": "echo 'Not implemented'",
"generate-api": "node node_modules/swagger-vue-generator/bin/generate-api.js --package-version v0 --source pkg/proto/v0/settings.swagger.json --moduleName settings --destination ui/client/settings/index.js"
"generate-api": "node node_modules/swagger-vue-generator/bin/generate-api.js --package-version v0 --source pkg/proto/v0/settings.swagger.json --moduleName settings --destination ui/client/settings/index.js",
"acceptance-tests": "cucumber-js --require-module @babel/register --require-module @babel/polyfill --require ${TEST_INFRA_DIRECTORY}/acceptance/setup.js --require ui/tests/acceptance/stepDefinitions --require ${TEST_INFRA_DIRECTORY}/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\""
},
"devDependencies": {
"@babel/core": "^7.7.7",
"@babel/polyfill": "^7.10.1",
"@babel/register": "^7.10.1",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-proposal-export-default-from": "^7.7.4",
"@babel/plugin-proposal-object-rest-spread": "^7.7.7",
@@ -30,6 +33,7 @@
"@rollup/plugin-commonjs": "^11.0.1",
"@rollup/plugin-json": "^4.0.1",
"@rollup/plugin-replace": "^2.3.0",
"archiver": "^4.0.1",
"axios": "^0.19.0",
"core-js": "3",
"cross-env": "^6.0.3",
@@ -53,7 +57,17 @@
"rollup-plugin-terser": "^5.1.3",
"rollup-plugin-vue": "^5.1.4",
"swagger-vue-generator": "^1.0.6",
"vue-template-compiler": "^2.6.11"
"vue-template-compiler": "^2.6.11",
"fs-extra": "^9.0.1",
"join-path": "^1.1.1",
"ldap": "^0.7.1",
"nightwatch": "^1.3.6",
"nightwatch-api": "^3.0.1",
"node-fetch": "^2.6.0",
"cucumber": "^6.0.5",
"cucumber-pretty": ">=6.0.0",
"xml-js": "^1.6.11",
"url-search-params-polyfill": "^8.1.0"
},
"browserslist": [
"> 1%",

View File

@@ -0,0 +1,57 @@
Feature: Set user specific settings
As a user
I want to set user specific settings
So that I can customize my OCIS experience to my liking
Background:
Given these users have been created with default attributes:
| username |
| user1 |
| user2 |
Scenario: Check the default settings
Given user "user1" has logged in using the webUI
And the user browses to the settings page
Then the setting "Language" should have value "Please select"
When the user browses to the files page
Then the files menu should be listed in language "English"
Scenario: changing the language
Given user "user1" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Deutsch"
Then the setting "Language" should have value "Deutsch"
When the user browses to the files page
And the user reloads the current page of the webUI
Then the files menu should be listed in language "Deutsch"
Scenario: changing the language only affects one user
Given user "user2" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Español"
Then the setting "Language" should have value "Español"
When the user browses to the files page
And the user reloads the current page of the webUI
Then the files menu should be listed in language "Español"
When the user re-logs in as "user1" using the webUI
And the user reloads the current page of the webUI
Then the files menu should be listed in language "English"
Scenario: Check the accounts menu when the language is changed
Given user "user2" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Deutsch"
And the user reloads the current page of the webUI
Then the setting "Language" should have value "Deutsch"
And the account menu should be listed in language "Deutsch"
When the user changes the language to "Français"
Then the account menu should be listed in language "Français"
Scenario: Check the files table header menu when the language is changed
Given user "user2" has logged in using the webUI
And the user browses to the settings page
When the user changes the language to "Deutsch"
Then the setting "Language" should have value "Deutsch"
When the user browses to the files page
And the user reloads the current page of the webUI
Then the files header should be displayed in language "Deutsch"

View File

@@ -0,0 +1,96 @@
const filesMenu = {
English: [
'All files',
'Shared with me',
'Shared with others',
'Trash bin'
],
Deutsch: [
'Alle Dateien',
'Mit mir geteilt',
'Mit anderen geteilt',
'Papierkorb'
],
Español: [
'Todos los archivos',
'Compartido conmigo',
'Compartido con otros',
'Papelera de reciclaje'
],
Français: [
'Tous les fichiers',
'Partagé avec moi',
'Partagé avec autres',
'Corbeille'
]
}
const accountMenu = {
English: [
'Manage your account',
'Log out'
],
Deutsch: [
'Verwalten Sie Ihr Benutzerkonto',
'Abmelden'
],
Español: [
'Administra tu cuenta',
'Salir'
],
Français: [
'Modifier votre compte',
'Se déconnecter'
]
}
const filesListHeaderMenu = {
English: [
'Name',
'Size',
'Updated',
'Actions'
],
Deutsch: [
'Name',
'Größe',
'Erneuert',
'Aktionen'
],
Español: [
'Nombre',
'Tamaño',
'Actualizado',
'Acciones'
],
Français: [
'Nom',
'Taille',
'Modifié',
'Actions'
]
}
exports.getFilesMenuForLanguage = function (language) {
const menuList = filesMenu[language]
if (menuList === undefined) {
throw new Error(`Menu for language ${language} is not available`)
}
return menuList
}
exports.getUserMenuForLanguage = function (language) {
const menuList = accountMenu[language]
if (menuList === undefined) {
throw new Error(`Menu for language ${language} is not available`)
}
return menuList
}
exports.getFilesHeaderMenuForLanguage = function (language) {
const menuList = filesListHeaderMenu[language]
if (menuList === undefined) {
throw new Error(`Menu for language ${language} is not available`)
}
return menuList
}

View File

@@ -0,0 +1,85 @@
module.exports = {
commands: {
getMenuList: async function () {
const menu = []
await this.isVisible('@openNavigationBtn', (res) => {
if (res.value) {
this.click('@openNavigationBtn')
}
})
await this.waitForElementVisible('@fileSidebarNavItem')
await this.api
.elements('@fileSidebarNavItem', result => {
result.value.map(item => {
this.api.elementIdText(item.ELEMENT, res => {
menu.push(res.value)
})
})
})
return menu
},
getUserMenu: async function () {
const menu = []
await this
.waitForElementVisible('@userMenuBtn')
.click('@userMenuBtn')
.waitForElementVisible('@userMenuContainer')
await this.api
.elements('@userMenuItem', result => {
result.value.map(item => {
this.api.elementIdText(item.ELEMENT, res => {
menu.push(res.value)
})
})
})
await this
.waitForElementVisible('@userMenuBtn')
.click('@userMenuBtn')
.waitForElementNotVisible('@userMenuContainer')
return menu
},
getFileHeaderItems: async function () {
const menu = []
await this.waitForElementVisible('@fileTableHeaderItems')
await this.api
.elements('@fileTableHeaderItems', result => {
result.value.map(item => {
this.api.elementIdText(item.ELEMENT, res => {
menu.push(res.value)
})
})
})
return menu
}
},
elements: {
pageHeader: {
selector: '.oc-page-title'
},
languageValue: {
selector: "//button[@id='single-choice-toggle-profile-language']",
locateStrategy: 'xpath'
},
fileSidebarNavItem: {
selector: '.oc-sidebar-nav-item'
},
openNavigationBtn: {
selector: '//button[@aria-label="Open navigation menu"]',
locateStrategy: 'xpath'
},
userMenuBtn: {
selector: '#_userMenuButton'
},
userMenuItem: {
selector: '#account-info-container li'
},
userMenuContainer: {
selector: '#account-info-container'
},
fileTableHeaderItems: {
selector: '//*[@id="files-table-header"]//span[not(*) and not(ancestor::label)]',
locateStrategy: 'xpath'
}
}
}

View File

@@ -0,0 +1,79 @@
const { client } = require('nightwatch-api')
const util = require('util')
module.exports = {
url: function () {
return this.api.launchUrl + '/#/settings'
},
commands: {
navigateAndWaitTillLoaded: async function () {
const url = this.url()
await await this.navigate(url)
while (true) {
let found = false
await this.waitForElementVisible('@pageHeader', 2000, 500, false)
await this.api
.elements('@pageHeader', result => {
if (result.value.length) {
found = true
}
})
if (found) {
break
}
await client.refresh()
}
return this.waitForElementVisible('@pageHeader')
},
getSettingsValue: async function (key) {
let output
switch (key) {
case 'Language':
await this.waitForElementVisible('@languageValue')
.getText('@languageValue', (result) => {
output = result.value
})
break
default:
throw new Error('failed to find the setting')
}
return output
},
changeSettings: async function (key, value) {
const selectXpath = util.format(this.elements.languageSelect.selector, value)
switch (key) {
case 'Language':
await this.waitForElementVisible('@languageValue')
.click('@languageValue')
.useXpath()
.waitForElementVisible(this.elements.languageDropdown.selector)
.click(selectXpath)
.waitForElementNotVisible(this.elements.languageDropdown.selector)
.useCss()
break
default:
throw new Error('failed to find the setting')
}
}
},
elements: {
pageHeader: {
selector: '.oc-page-title'
},
languageValue: {
selector: "//label[.='Language']/..//button[starts-with(@id, 'single-choice-toggle')]",
locateStrategy: 'xpath'
},
languageDropdown: {
selector: "//label[.='Language']/..//div[starts-with(@id, 'single-choice-drop')]",
locateStrategy: 'xpath'
},
languageSelect: {
selector: "//label[.='Language']/..//div[starts-with(@id, 'single-choice-drop')]//label[normalize-space()='%s']",
locateStrategy: 'xpath'
}
}
}

View File

@@ -0,0 +1,55 @@
const assert = require('assert')
const path = require('path')
const fs = require('fs-extra')
const { client } = require('nightwatch-api')
const { Given, When, Then, After } = require('cucumber')
const languageHelper = require('../helpers/language')
Given('the user browses to the settings page', function () {
return client.page.settingsPage().navigateAndWaitTillLoaded()
})
Then('the setting {string} should have value {string}', async function (setting, result) {
const actual = await client.page.settingsPage().getSettingsValue(setting)
assert.strictEqual(actual, result, 'The setting value doesnt matches to ' + result)
})
When('the user changes the language to {string}', async function (value) {
await client.page.settingsPage().changeSettings('Language', value)
})
Then('the files menu should be listed in language {string}', async function (language) {
const menu = await client.page.filesPageSettingsContext().getMenuList()
const expected = languageHelper.getFilesMenuForLanguage(language)
assert.deepEqual(menu, expected, 'the menu list were not same')
})
Then('the account menu should be listed in language {string}', async function (language) {
const menu = await client.page.filesPageSettingsContext().getUserMenu()
const expected = languageHelper.getUserMenuForLanguage(language)
assert.deepEqual(menu, expected, 'the menu list were not same')
})
Then('the files header should be displayed in language {string}', async function (language) {
const items = await client.page.filesPageSettingsContext().getFileHeaderItems()
const expected = languageHelper.getFilesHeaderMenuForLanguage(language)
assert.deepEqual(items, expected, 'the menu list were not same')
})
After(async function () {
const directory = path.join(client.globals.settings_store, 'values')
try {
console.log('Elements')
fs.readdirSync(directory).map(element => {
console.log(element)
})
} catch (err) {
console.log('Error while reading the settings values from file system... ')
}
try {
fs.emptyDirSync(directory)
} catch (err) {
console.log('Error while clearing settings values from file system')
console.log('No settings may have been changed by the tests')
}
})

View File

@@ -0,0 +1,16 @@
---
# OpenID Connect client registry.
clients:
- id: phoenix
name: OCIS
application_type: web
insecure: yes
trusted: yes
redirect_uris:
- https://ocis-server:9200/oidc-callback.html
- https://ocis-server:9200/
origins:
- https://ocis-server:9200
authorities:

View File

@@ -0,0 +1,28 @@
{
"server": "https://ocis-server:9200",
"theme": "owncloud",
"version": "0.1.0",
"openIdConnect": {
"metadata_url": "https://ocis-server:9200/.well-known/openid-configuration",
"authority": "https://ocis-server:9200",
"client_id": "phoenix",
"response_type": "code",
"scope": "openid profile email"
},
"apps": [
"files",
"draw-io",
"pdf-viewer",
"markdown-editor",
"media-viewer"
],
"external_apps": [
{
"id": "settings",
"path": "https://ocis-server:9200/settings.js",
"config": {
"url": "https://ocis-server:9200"
}
}
]
}

View File

@@ -0,0 +1,82 @@
{
"HTTP": {
"Namespace": "com.owncloud"
},
"policy_selector": {
"static": {
"policy": "reva"
}
},
"policies": [
{
"name": "reva",
"routes": [
{
"endpoint": "/",
"backend": "http://localhost:9100"
},
{
"endpoint": "/.well-known/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/konnect/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/signin/",
"backend": "http://localhost:9130"
},
{
"endpoint": "/ocs/",
"backend": "http://localhost:9140"
},
{
"type": "regex",
"endpoint": "/ocs/v[12].php/cloud/user",
"backend": "http://localhost:9110"
},
{
"endpoint": "/remote.php/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/dav/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/webdav/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/status.php",
"backend": "http://localhost:9140"
},
{
"endpoint": "/index.php/",
"backend": "http://localhost:9140"
},
{
"endpoint": "/data",
"backend": "http://localhost:9140"
},
{
"endpoint": "/api/v0/accounts",
"backend": "http://localhost:9181"
},
{
"endpoint": "/accounts.js",
"backend": "http://localhost:9181"
},
{
"endpoint": "/api/v0/settings",
"backend": "http://localhost:9190"
},
{
"endpoint": "/settings.js",
"backend": "http://localhost:9190"
}
]
}
]
}

61
ui/tests/run-acceptance-test.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
if [ -z "$PHOENIX_PATH" ]
then
echo "PHOENIX_PATH env variable is not set, cannot find files for tests infrastructure"
exit 1
fi
if [ -z "$OCIS_SKELETON_DIR" ]
then
echo "OCIS_SKELETON_DIR env variable is not set, cannot find skeleton directory"
exit 1
fi
if [ -z "$PHOENIX_CONFIG" ]
then
echo "PHOENIX_CONFIG env variable is not set, cannot find phoenix config file"
exit 1
fi
if [ -z "$1" ]
then
echo "Features path not given, exiting test run"
exit 1
fi
trap clean_up SIGHUP SIGINT SIGTERM
if [ -z "$TEST_INFRA_DIRECTORY" ]
then
cleanup=true
testFolder=$(cat < /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
printf "creating folder $testFolder for Test infrastructure setup\n\n"
export TEST_INFRA_DIRECTORY=$testFolder
fi
clean_up() {
if $cleanup
then
if [ -d "$testFolder" ]; then
printf "\n\n\n\nDeleting folder $testFolder Test infrastructure setup..."
rm -rf "$testFolder"
fi
fi
}
trap clean_up SIGHUP SIGINT SIGTERM EXIT
cp -r "$PHOENIX_PATH/tests" "./$testFolder"
export NODE_TLS_REJECT_UNAUTHORIZED='0'
export SERVER_HOST=${SERVER_HOST:-https://localhost:9200}
export BACKEND_HOST=${BACKEND_HOST:-https://localhost:9200}
export OCIS_SETTINGS_STORE=${OCIS_SETTINGS_STORE:-"/var/tmp/ocis-settings"}
export RUN_ON_OCIS=true
export TEST_TAGS=${TEST_TAGS:-"not @skip"}
yarn run acceptance-tests "$1"
status=$?
exit $status

1923
yarn.lock
View File

File diff suppressed because it is too large Load Diff