diff --git a/package.json b/package.json index 8358e67..39c97a1 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@wdio/spec-reporter": "^6.8.1", "@wdio/sync": "^6.10.4", "chromedriver": "^86.0.0", + "deepmerge": "^4.2.2", "moment": "^2.27.0", "wdio-applitools-cucumber-service": "^1.0.6", "wdio-chromedriver-service": "^6.0.4", @@ -33,11 +34,12 @@ "request": "^2.88.0" }, "_moduleAliases": { - "@support": "./support", - "@page_objects": "./page_objects" + "#support": "./support", + "#page_objects": "./page_objects" }, "_moduleAliasIgnoreWarning": true, "scripts": { + "preinstall": "command -v link-module-alias && link-module-alias clean || true", "postinstall": "link-module-alias", "lint": "./node_modules/eslint/bin/eslint.js . --fix", "browserstack": "./node_modules/.bin/wdio wdio.remote.conf.js", diff --git a/page_objects/Dashboard.js b/page_objects/Dashboard.js index 1bc11dc..fbdac5f 100644 --- a/page_objects/Dashboard.js +++ b/page_objects/Dashboard.js @@ -1,5 +1,5 @@ import Page from './Page'; -import { waitForElementToExist, waitForVisible } from '@support/wait'; +import { waitForElementToExist, waitForVisible } from '#support/wait'; class Dashboard extends Page { get headerDiv () { return browser.$('[data-test="dashboards-bar"]'); } diff --git a/page_objects/Login.js b/page_objects/Login.js index ead26ea..0c44065 100644 --- a/page_objects/Login.js +++ b/page_objects/Login.js @@ -1,5 +1,5 @@ import Page from './Page'; -import { waitForElementToExist, waitForVisible } from '@support/wait'; +import { waitForElementToExist, waitForVisible } from '#support/wait'; class Login extends Page { get loginForm () { return browser.$('#loginForm'); } diff --git a/page_objects/capture/CaptureHeaderBar.js b/page_objects/capture/CaptureHeaderBar.js index 8dc3c07..39ae60c 100644 --- a/page_objects/capture/CaptureHeaderBar.js +++ b/page_objects/capture/CaptureHeaderBar.js @@ -1,5 +1,5 @@ import Page from '../Page' -import { waitForWindowToLoad } from '@support/wait' +import { waitForWindowToLoad } from '#support/wait' class CaptureHeaderBar extends Page { get newEventButton() { diff --git a/page_objects/capture/CaptureIndexPage.js b/page_objects/capture/CaptureIndexPage.js index f220f78..c1609df 100644 --- a/page_objects/capture/CaptureIndexPage.js +++ b/page_objects/capture/CaptureIndexPage.js @@ -1,5 +1,5 @@ import Page from '../Page' -import { waitForWindowToLoad, waitForElementToExist } from '@support/wait' +import { waitForWindowToLoad, waitForElementToExist } from '#support/wait' class CaptureIndexPage extends Page { get orgUnits() { @@ -32,7 +32,7 @@ class CaptureIndexPage extends Page { } selectProgram(name) { - waitForElementToExist('#program-selector .Select-placeholder'); + waitForElementToExist(browser.$('#program-selector .Select-placeholder')); browser.$('#program-selector .Select-placeholder').click(); browser.$('.Select-menu-outer').$('//*[contains(text(), "' + name + '")]').click(); diff --git a/page_objects/capture/CaptureNewEventForm.js b/page_objects/capture/CaptureNewEventForm.js index 1bdd907..47b94aa 100644 --- a/page_objects/capture/CaptureNewEventForm.js +++ b/page_objects/capture/CaptureNewEventForm.js @@ -1,5 +1,5 @@ import Page from '../Page' -import { waitForWindowToLoad, waitForVisible, waitForClickable } from '@support/wait' +import { waitForWindowToLoad, waitForVisible, waitForClickable } from '#support/wait' import CaptureCommentsSection from './CaptureCommentsSection'; var moment = require('moment'); diff --git a/page_objects/capture/CaptureViewEventPage.js b/page_objects/capture/CaptureViewEventPage.js index 349bc6d..8fe6227 100644 --- a/page_objects/capture/CaptureViewEventPage.js +++ b/page_objects/capture/CaptureViewEventPage.js @@ -1,5 +1,5 @@ import Page from '../Page' -import { waitForWindowToLoad} from '@support/wait'; +import { waitForWindowToLoad} from '#support/wait'; class CaptureViewEventPage extends Page { open(eventId) { super.open('dhis-web-capture/#/viewEvent?viewEventId=' + eventId); diff --git a/services/wdio-jira-integration-service.js b/services/wdio-jira-integration-service.js index df556bd..07b1cd4 100644 --- a/services/wdio-jira-integration-service.js +++ b/services/wdio-jira-integration-service.js @@ -8,7 +8,7 @@ class WdioJiraService { } _configure() { - if (!this.options.isEnabled) { + if (!this.options.isEnabled || this.options.isEnabled == 'false') { return; } diff --git a/step_definitions/Then.js b/step_definitions/Then.js index d420a44..0593472 100644 --- a/step_definitions/Then.js +++ b/step_definitions/Then.js @@ -1,5 +1,5 @@ import { Then } from 'cucumber'; -import { checkTitle } from '@support/check'; +import { checkTitle } from '#support/check'; Then( /^I expect that the title is( not)* "([^"]*)?"$/, diff --git a/step_definitions/dhis2/apps/analyticsApps.js b/step_definitions/dhis2/apps/analyticsApps.js index a37f6d5..9fcca8e 100644 --- a/step_definitions/dhis2/apps/analyticsApps.js +++ b/step_definitions/dhis2/apps/analyticsApps.js @@ -1,7 +1,7 @@ -import { getFilteredConsoleLog, getConsoleLog, saveScreenshot } from '@support/action'; -import { waitForVisible, waitForWindowToLoad } from '@support/wait'; +import { getFilteredConsoleLog, getConsoleLog, saveScreenshot } from '#support/action'; +import { waitForVisible, waitForWindowToLoad } from '#support/wait'; import { Given, Then } from 'cucumber'; -import { reportStep } from '@support/reporting' +import { reportStep } from '#support/reporting' let listOfFavorites = []; let appName = ''; diff --git a/step_definitions/dhis2/apps/apps.js b/step_definitions/dhis2/apps/apps.js index 7cb2d3d..1f6acf9 100644 --- a/step_definitions/dhis2/apps/apps.js +++ b/step_definitions/dhis2/apps/apps.js @@ -1,7 +1,7 @@ -import { getConsoleLog, getFilteredConsoleLog, saveScreenshot } from '@support/action'; -import { waitForVisible, waitForWindowToLoad } from '@support/wait'; +import { getConsoleLog, getFilteredConsoleLog, saveScreenshot } from '#support/action'; +import { waitForVisible, waitForWindowToLoad } from '#support/wait'; import { Given, Then } from 'cucumber'; -import { reportStep } from '@support/reporting' +import { reportStep } from '#support/reporting' const listOfApps = ['dhis-web-dataentry/index.action', 'dhis-web-approval/index.action']; Given(/^I have a list of installed core apps$/, () => { diff --git a/step_definitions/dhis2/capture/capture.js b/step_definitions/dhis2/capture/capture.js index 9aedb80..5e9c053 100644 --- a/step_definitions/dhis2/capture/capture.js +++ b/step_definitions/dhis2/capture/capture.js @@ -1,6 +1,6 @@ import { Given, Then, When } from 'cucumber'; -import { captureHeaderBar, captureIndexPage, captureNewEventForm, captureViewEventPage, captureCommentsSection } from '@page_objects/capture'; -import { waitForWindowToLoad } from '@support/wait'; +import { captureHeaderBar, captureIndexPage, captureNewEventForm, captureViewEventPage, captureCommentsSection } from '#page_objects/capture'; +import { waitForWindowToLoad } from '#support/wait'; Given(/^I open the capture app/, () => { captureIndexPage.open(); diff --git a/step_definitions/dhis2/dashboard/dashboard.js b/step_definitions/dhis2/dashboard/dashboard.js index d68140e..db883c2 100644 --- a/step_definitions/dhis2/dashboard/dashboard.js +++ b/step_definitions/dhis2/dashboard/dashboard.js @@ -1,9 +1,9 @@ -import { dashboardPage } from '@page_objects/Dashboard'; -import { isVisible } from '@support/check'; -import { getConsoleLog, getFilteredConsoleLog, saveScreenshot } from '@support/action'; -import { waitForElementToExist, waitForWindowToLoad } from '@support/wait'; +import { dashboardPage } from '#page_objects/Dashboard'; +import { isVisible } from '#support/check'; +import { getConsoleLog, getFilteredConsoleLog, saveScreenshot } from '#support/action'; +import { waitForElementToExist, waitForWindowToLoad } from '#support/wait'; import { Then } from 'cucumber'; -import { reportStep } from '@support/reporting' +import { reportStep } from '#support/reporting' Then( /^I expect that header is visible$/, diff --git a/step_definitions/dhis2/given.js b/step_definitions/dhis2/given.js index ddca2f4..bfece9e 100644 --- a/step_definitions/dhis2/given.js +++ b/step_definitions/dhis2/given.js @@ -1,29 +1,30 @@ import { Given } from 'cucumber'; -import { isVisible} from '@support/check'; -import { waitForVisible } from '@support/wait'; +import { isVisible} from '#support/check'; +import { waitForVisible } from '#support/wait'; -import { login } from '@support/action'; -import { dashboardPage } from '@page_objects/Dashboard'; +import { login } from '#support/action'; +import { dashboardPage } from '#page_objects/Dashboard'; - Given( - /^I am logged in$/, - () => { - // login as standard user - login('system', 'System123'); - waitForVisible(dashboardPage.mainPageDiv); - isVisible(dashboardPage.mainPageDiv); - } - ); +Given( + /^I am logged in$/, + () => { + // login as standard user + login(browser.config.superUser, browser.config.superUserPassword); + waitForVisible(dashboardPage.mainPageDiv); + isVisible(dashboardPage.mainPageDiv); + } +); - Given( - /^I am authenticated$/, - () => { - login('system', 'System123'); +Given( + /^I am authenticated$/, + () => { + login(browser.config.superUser, browser.config.superUserPassword); + + browser.waitUntil(() => { + const url = browser.getUrl(); + return url.indexOf('dhis-web') > -1 && url.indexOf('#') > -1 && url.indexOf('login.action') === -1; + }, 10000); + } +); - browser.waitUntil(() => { - const url = browser.getUrl(); - return url.indexOf('dhis-web') > -1 && url.indexOf('#') > -1 && url.indexOf('login.action') === -1; - }, 10000); - } - ); diff --git a/step_definitions/dhis2/then.js b/step_definitions/dhis2/then.js index d569248..dc2b8b0 100644 --- a/step_definitions/dhis2/then.js +++ b/step_definitions/dhis2/then.js @@ -1,9 +1,9 @@ import { Then } from 'cucumber'; -import { isVisible} from '@support/check'; -import { waitForElementToExist } from '@support/wait'; -import { logout } from '@support/action'; -import { loginPage } from '@page_objects/Login'; -import { dashboardPage } from '@page_objects/Dashboard'; +import { isVisible} from '#support/check'; +import { waitForElementToExist } from '#support/wait'; +import { logout } from '#support/action'; +import { loginPage } from '#page_objects/Login'; +import { dashboardPage } from '#page_objects/Dashboard'; Then( /^I should( not)? be authenticated$/, diff --git a/step_definitions/dhis2/when.js b/step_definitions/dhis2/when.js index 9a13636..e35a98f 100644 --- a/step_definitions/dhis2/when.js +++ b/step_definitions/dhis2/when.js @@ -1,4 +1,4 @@ -import { login} from '@support/action'; +import { login} from '#support/action'; import { When } from 'cucumber'; When( diff --git a/support/action/dhis2/login.js b/support/action/dhis2/login.js index 8b70695..151c8af 100644 --- a/support/action/dhis2/login.js +++ b/support/action/dhis2/login.js @@ -1,4 +1,4 @@ -import { loginPage } from '@page_objects/Login'; +import { loginPage } from '#page_objects/Login'; module.exports = (username, password) => { loginPage.doLogin(username, password); diff --git a/support/reporting/reportStep.js b/support/reporting/reportStep.js index 8fecee1..851033d 100644 --- a/support/reporting/reportStep.js +++ b/support/reporting/reportStep.js @@ -1,4 +1,4 @@ -import { saveScreenshot } from '@support/action'; +import { saveScreenshot } from '#support/action'; import fs from 'fs'; module.exports = (stepName, expectedResult, status, allureContent) => { diff --git a/support/wait/waitForWindowToLoad.js b/support/wait/waitForWindowToLoad.js index a7824cd..f503df7 100644 --- a/support/wait/waitForWindowToLoad.js +++ b/support/wait/waitForWindowToLoad.js @@ -17,7 +17,6 @@ module.exports = () => { if (newSource === source) { if (retries <= 0) { - console.log('finished waiting') return true; } retries--; diff --git a/wdio.conf.js b/wdio.conf.js index 30e5d89..bbd260c 100644 --- a/wdio.conf.js +++ b/wdio.conf.js @@ -5,6 +5,8 @@ const drivers = { chrome: { version: '88.0.4324.96' }, // https://chromedriver.chromium.org/ } exports.config = { + superUser: process.env.SUPER_USER || 'system', + superUserPassword: process.env.SUPER_USER_PASSWORD || 'System123', // // ==================== // Runner Configuration @@ -94,7 +96,7 @@ exports.config = { services: [ [ jiraService, { - isEnabled: true, + isEnabled: process.env.JIRA_ENABLED || true, instanceUrl: "https://jira.dhis2.org", username: process.env.JIRA_USERNAME, password: process.env.JIRA_PASSWORD, @@ -285,6 +287,15 @@ exports.config = { // Suites // ====== suites: { + smoke: [ + './features/apps/dataVisualiser.feature', + './features/apps/eventVisualiser.feature', + './features/apps/eventsReport.feature', + './features/apps/maps.feature', + './features/apps/pivotTables.feature', + './features/apps/apps.feature', + './features/dashboardPage.feature' + ], login: [ './features/loginPage.feature' ], diff --git a/wdio.remote.conf.js b/wdio.remote.conf.js index e996be4..f104634 100644 --- a/wdio.remote.conf.js +++ b/wdio.remote.conf.js @@ -1,48 +1,13 @@ -const chai = require('chai'); -require('@babel/register'); +const merge = require('deepmerge'); +const wdioConf = require('./wdio.conf.js') const jiraService = require('./services/wdio-jira-integration-service').default; -exports.config = { +const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray + +exports.config = merge(wdioConf.config, { runner: 'local', + maxInstances: process.env.DEBUG === '1' ? 1 : 3, user: process.env.USERNAME, key: process.env.KEY, - // - // ==================== - // Runner Configuration - // ==================== - // - // WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or - // on a remote machine). - // - // Override default path ('/wd/hub') for chromedriver service. - specs: [ - './features/**/*.feature' - ], - // Patterns to exclude. - exclude: [ - // 'path/to/excluded/files' - ], - // - // ============ - // Capabilities - // ============ - // Define your capabilities here. WebdriverIO can run multiple capabilities at the same - // time. Depending on the number of capabilities, WebdriverIO launches several test - // sessions. Within your capabilities you can overwrite the spec and exclude options in - // order to group specific specs to a specific capability. - // - // First, you can define how many instances should be started at the same time. Let's - // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have - // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec - // files and you set maxInstances to 10, all spec files will get tested at the same time - // and 30 processes will get spawned. The property handles how many capabilities - // from the same test should run tests. - // - maxInstances: process.env.DEBUG === '1' ? 1 : 10, - // - // If you have trouble getting all important capabilities together, check out the - // Sauce Labs platform configurator - a great tool to configure your capabilities: - // https://docs.saucelabs.com/reference/platforms-configurator - // capabilities: [{ // maxInstances can get overwritten per capability. So if you have an in-house Selenium // grid with only 5 firefox instances available you can make sure that not more than @@ -56,7 +21,7 @@ exports.config = { 'osVersion': '10', 'local': 'false', 'seleniumVersion': '3.14.0' - }, + }, 'goog:chromeOptions': { 'args': [ '--allow-running-insecure-content', @@ -64,42 +29,9 @@ exports.config = { ] } }], - - screenshotPath: './errorShots/', - // - // =================== - // Test Configurations - // =================== - // Define all options that are relevant for the WebdriverIO instance here - // - // Level of logging verbosity: trace | debug | info | warn | error | silent - logLevel: 'error', - coloredLogs: true, - bail: 0, - // - // Set a base URL in order to shorten url command calls. If your `url` parameter starts - // with `/`, the base url gets prepended, not including the path portion of your baseUrl. - // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url - // gets prepended directly. - baseUrl: 'https://play.dhis2.org/dev/', - // - // Default timeout for all waitFor* commands. - waitforTimeout: 30000, - // - // Default timeout in milliseconds for request - // if Selenium Grid doesn't send response - connectionRetryTimeout: 90000, - // - // Default request retries count - connectionRetryCount: 3, - // - // Test runner services - // Services take over a specific job you don't want to take care of. They enhance - // your test setup with almost no effort. Unlike plugins, they don't add new - // commands. Instead, they hook themselves up into the test process. services: [ [ jiraService, { - isEnabled: true, + isEnabled: process.env.JIRA_ENABLED || true, instanceUrl: "https://jira.dhis2.org", username: process.env.JIRA_USERNAME, password: process.env.JIRA_PASSWORD, @@ -109,214 +41,7 @@ exports.config = { }], 'browserstack' ], + waitforTimeout: 30000 +}, {arrayMerge: overwriteMerge}) - seleniumLogs: './logs', - - /* seleniumInstallArgs: { version: '3.4.0' }, - seleniumArgs: { version: '3.4.0' }, */ - /* seleniumInstallArgs: { - version: "3.141.59", - drivers: { - chrome: { - version: '77.0.3865.40', // depending on when u see this, you may want something newer - arch: process.arch, - baseURL: 'https://chromedriver.storage.googleapis.com', - }, - } - }, - seleniumArgs: { - version: "3.141.59", - drivers: { - chrome: { - version: '77.0.3865.40', - arch: process.arch - }, - }, - }, */ - - // Framework you want to run your specs with. - // The following are supported: Mocha, Jasmine, and Cucumber - // see also: https://webdriver.io/docs/frameworks.html - // - // Make sure you have the wdio adapter package for the specific framework installed - // before running any tests. - framework: 'cucumber', - // - // The number of times to retry the entire specfile when it fails as a whole - // specFileRetries: 1, - // - // Test reporter for stdout. - // The only one supported by default is 'dot' - // see also: https://webdriver.io/docs/dot-reporter.html - reporters: [ - 'spec', - ['allure', { - outputDir: './reports/allure-results', - disableWebdriverStepsReporting: true, - useCucumberStepReporter: true, - disableWebdriverScreenshotsReporting: false - }] - ], - - // - // If you are using Cucumber you need to specify the location of your step definitions. - cucumberOpts: { - require: [ - './step_definitions/**/**/*.js' - ], - backtrace: true, // show full backtrace for errors - requireModule: [], // ("extension:module") require files with the given EXTENSION after requiring MODULE (repeatable) - dryRun: false, // invoke formatters without executing steps - failFast: false, // abort the run on first failure - format: ['pretty'], // (type[:path]) specify the output format, optionally supply PATH to redirect formatter output (repeatable) - colors: true, // disable colors in formatter output - snippets: true, // hide step definition snippets for pending steps - source: true, // hide source uris - profile: [], // (name) specify the profile to use - strict: false, // fail if there are any undefined or pending steps - tagExpression: '', // (expression) only execute the features or scenarios with tags matching the expression - timeout: 60000, // timeout for step definitions - ignoreUndefinedDefinitions: false, // Enable this config to treat undefined definitions as warnings. - failAmbiguousDefinitions: true - }, - - // - // ===== - // Hooks - // ===== - // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance - // it and to build services around it. You can either apply a single function or an array of - // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got - // resolved to continue. - /** - * Gets executed once before all workers get launched. - * @param {Object} config wdio configuration object - * @param {Array.} capabilities list of capabilities details - */ - // onPrepare: function (config, capabilities) { - // }, - /** - * Gets executed just before initialising the webdriver session and test framework. It allows you - * to manipulate configurations depending on the capability or spec. - * @param {Object} config wdio configuration object - * @param {Array.} capabilities list of capabilities details - * @param {Array.} specs List of spec file paths that are to be run - */ - // beforeSession: function (config, capabilities, specs) { - // }, - /** - * Gets executed before test execution begins. At this point you can access to all global - * variables like `browser`. It is the perfect place to define custom commands. - * @param {Array.} capabilities list of capabilities details - * @param {Array.} specs List of spec file paths that are to be run - */ - before: function (capabilities, specs) { - /** - * Setup the Chai assertion framework - */ - global.__basedir = __dirname; - global.expect = chai.expect; - global.assert = chai.assert; - global.should = chai.should(); - global.allure = require('@wdio/allure-reporter').default - }, - /** - * Runs before a WebdriverIO command gets executed. - * @param {String} commandName hook command name - * @param {Array} args arguments that command would receive - */ - // beforeCommand: function (commandName, args) { - // }, - /** - * Runs before a Cucumber feature - */ - // beforeFeature: function (uri, feature, scenarios) { - // }, - /** - * Runs before a Cucumber scenario - */ - // beforeScenario: function (uri, feature, scenario, sourceLocation) { - // }, - /** - * Runs before a Cucumber step - */ - // beforeStep: function (uri, feature, stepData, context) { - // }, - /** - * Runs after a Cucumber step - */ - afterStep: function (test, context, { error, result, duration, passed, retries }) { - if (error) { - browser.takeScreenshot(); - } - }, - /** - * Runs after a Cucumber scenario - */ - // afterScenario: function (uri, feature, scenario, result, sourceLocation) { - // }, - /** - * Runs after a Cucumber feature - */ - // afterFeature: function (uri, feature, scenarios) { - // }, - /** - * Runs after a WebdriverIO command gets executed - * @param {String} commandName hook command name - * @param {Array} args arguments that command would receive - * @param {Number} result 0 - command success, 1 - command error - * @param {Object} error error object if any - */ - // afterCommand: function (commandName, args, result, error) { - // }, - /** - * Gets executed after all tests are done. You still have access to all global variables from - * the test. - * @param {Number} result 0 - test pass, 1 - test fail - * @param {Array.} capabilities list of capabilities details - * @param {Array.} specs List of spec file paths that ran - */ - // after: function (result, capabilities, specs) { - // }, - /** - * Gets executed right after terminating the webdriver session. - * @param {Object} config wdio configuration object - * @param {Array.} capabilities list of capabilities details - * @param {Array.} specs List of spec file paths that ran - */ - // afterSession: function (config, capabilities, specs) { - // }, - /** - * Gets executed after all workers got shut down and the process is about to exit. An error - * thrown in the onComplete hook will result in the test run failing. - * @param {Object} exitCode 0 - success, 1 - fail - * @param {Object} config wdio configuration object - * @param {Array.} capabilities list of capabilities details - * @param {} results object containing test results - */ - // onComplete: function(exitCode, config, capabilities, results) { - // }, - /** - * Gets executed when a refresh happens. - * @param {String} oldSessionId session ID of the old session - * @param {String} newSessionId session ID of the new session - */ - //onReload: function(oldSessionId, newSessionId) { - //} - // ====== - // Suites - // ====== - suites: { - login: [ - './features/loginPage.feature' - ], - appsLong: [ - './features/apps/dataVisualiser.feature', - './features/apps/eventVisualiser.feature', - './features/apps/eventsReport.feature', - './features/apps/maps.feature', - './features/apps/pivotTables.feature' - ] - } -};