From b80756b687957245fb79aa3656616509e4d2dfbb Mon Sep 17 00:00:00 2001 From: Dawid Majsnerowski Date: Fri, 29 Nov 2019 22:16:18 +0100 Subject: [PATCH] BES-26 | First test for BestNotes --- package-lock.json | 53 ++++++ package.json | 1 + test/config/base.conf.js | 3 + test/specs/base/base.js | 168 ++++++++++++++++++++ test/specs/base/common.js | 10 ++ test/specs/base/navigation.js | 14 ++ test/specs/components/login.js | 15 ++ test/specs/suites/desktop/loginpage.test.js | 17 ++ test/specs/testfile.webdriver.js | 9 -- 9 files changed, 281 insertions(+), 9 deletions(-) create mode 100644 test/specs/base/base.js create mode 100644 test/specs/base/common.js create mode 100644 test/specs/base/navigation.js create mode 100644 test/specs/components/login.js create mode 100644 test/specs/suites/desktop/loginpage.test.js delete mode 100644 test/specs/testfile.webdriver.js diff --git a/package-lock.json b/package-lock.json index c32d3f1..3293ef4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -347,6 +347,12 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", @@ -538,6 +544,20 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -553,6 +573,12 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", @@ -803,6 +829,15 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -1166,6 +1201,12 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -2276,6 +2317,12 @@ "pinkie-promise": "^2.0.0" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -2778,6 +2825,12 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", diff --git a/package.json b/package.json index 0079a61..c894fb6 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@wdio/mocha-framework": "^5.16.5", "@wdio/spec-reporter": "^5.16.5", "@wdio/sync": "^5.16.5", + "chai": "^4.2.0", "chromedriver": "^78.0.1", "wdio-chromedriver-service": "^5.0.2" }, diff --git a/test/config/base.conf.js b/test/config/base.conf.js index 00993ac..436bf60 100644 --- a/test/config/base.conf.js +++ b/test/config/base.conf.js @@ -1,6 +1,9 @@ exports.config = { runner: 'local', path: '/', + suites: { + login: ['./test/specs/suites/desktop/loginpage.test.js'], + }, specs: [ './test/specs/**/*.js' ], diff --git a/test/specs/base/base.js b/test/specs/base/base.js new file mode 100644 index 0000000..c576431 --- /dev/null +++ b/test/specs/base/base.js @@ -0,0 +1,168 @@ +class Base { + click(selector, elementName) { + try { + $(selector).scrollIntoView({ block: 'center' }); + $(selector).waitForEnabled(); + $(selector).click(); + console.log(`${elementName} was clicked`); + } catch (err) { + console.log(`${elementName} was not clicked. Exception: ${err}`); + } + } + + clickNth(selector, position, elementName) { + try { + $$(selector)[position].scrollIntoView({ block: 'center' }); + $$(selector)[position].waitForEnabled(); + $$(selector)[position].click(); + console.log(`${elementName} with position: ${position} was clicked`); + } catch (err) { + console.log(`${elementName} with position: ${position} was not clicked. Exception: ${err}`); + } + } + + clearInput(selector) { + try { + const valueLength = $(selector).getValue().length; + const backSpaces = new Array(valueLength).fill('Backspace'); + $(selector).setValue(backSpaces); + console.log(`${selector} has length: ${valueLength} and was cleared`); + } catch (e) { + console.log(`${selector} was not cleared with exception: ${e}`); + } + } + + fillIn(selector, text, elementName) { + console.log(`${elementName} is displayed`); + try { + this.clearInput(selector); + $(selector).setValue(text); + console.log(`${text} was added to ${elementName}`); + } catch (err) { + console.log(`An exception occurred when adding a text to the element: ${err}`); + } + } + + fillInNth(selectorList, position, text, elementName) { + try { + $$(selectorList)[position].setValue(text); + console.log(`${text} was added to ${elementName}`); + } catch (err) { + console.log(`An exception occurred when adding a text to the element: ${err}`); + } + } + + getAttribute(selector, attribute, elementName) { + let attributeValue = null; + try { + console.log(`${elementName} was displayed`); + attributeValue = $(selector).getAttribute(attribute); + console.log(`${elementName} had value: ${attributeValue}`); + } catch (err) { + console.log(`Could not get ${elementName}. Exception: ${err}`); + } + + return attributeValue; + } + + getLinkFromElementsArray(selector, position, elementName) { + let href = null; + try { + href = $$(selector)[position].$('a').getAttribute('href').replace('%20', '_'); + console.log(`Link for ${elementName} with position ${position} has value: ${href}`); + } catch (err) { + console.log(`Could not get link for ${elementName}. Exception: ${err}`); + } + + return href; + } + + isEnabled(selector, elementName) { + console.log(`${elementName} is displayed`); + const isEnabled = $(selector).isEnabled(); + console.log(`${elementName} is enabled: ${isEnabled}`); + + return isEnabled; + } + + isDisplayed(selector, elementName, customTimeout) { + let isDisplayed = false; + try { + isDisplayed = $(selector).isDisplayed(customTimeout, true); + console.log(`${elementName} is displayed: ${isDisplayed}`); + } catch (err) { + console.log(`${elementName} is displayed: ${isDisplayed}. Exception: ${err}`); + } + + return isDisplayed; + } + + isNthDisplayed(selectorsList, position, elementName, customTimeout) { + let isDisplayed = false; + try { + isDisplayed = $$(selectorsList)[position].isDisplayed(customTimeout, true); + console.log(`${elementName} with position ${position} is displayed: ${isDisplayed}`); + } catch (err) { + console.log(`${elementName} with position ${position} is displayed: ${isDisplayed}. Exception: ${err}`); + } + + return isDisplayed; + } + + waitForDisplayed(selector, elementName) { + browser.waitUntil(() => { + try { + return $(selector).isDisplayed(); + } catch (e) { + console.log(`${elementName} is not displayed. Exception: ${e}`); + return false; + } + }, 5000, `Expected ${selector} to be displayed after 5s`); + } + + waitForNthElementDisplayed(selectorList, position, elementName) { + browser.waitUntil(() => { + try { + return $$(selectorList)[position].isDisplayed(); + } catch (e) { + console.log(`${elementName} with position ${position} is not displayed. Exception: ${e}`); + return false; + } + }, 5000, `Expected ${elementName} with position ${position} to be displayed after 5s`, 500); + } + + waitForNotDisplayed(selector, elementName, customTimeout) { + browser.waitUntil(() => { + try { + return !$(selector).isDisplayed(customTimeout, true); + } catch (e) { + console.log(`${elementName} is still displayed. Exception: ${e}`); + return true; + } + }, 5000, `Expected ${elementName} to be displayed after 5s`, 500); + } + + waitForEnabled(selector, elementName) { + browser.waitUntil(() => { + try { + return !$(selector).isEnabled(); + } catch (e) { + console.log(`${elementName} is not enabled. Exception: ${e}`); + return true; + } + }, 5000, `Expected ${selector} to be enabled after 5s`, 500); + } + + isChildDisplayedForParent(parentElementSelector, position, childElementSelector, childElementName) { + const isDisplayed = $$(parentElementSelector)[position].$(childElementSelector).isDisplayed(); + console.log(`${childElementName} is displayed: ${isDisplayed}`); + + return isDisplayed; + } + + wait(timeout) { + setTimeout(() => { console.log(`This is a explicit wait of ${timeout}`); }, timeout); + } +} + +module.exports = new Base(); \ No newline at end of file diff --git a/test/specs/base/common.js b/test/specs/base/common.js new file mode 100644 index 0000000..f7e103a --- /dev/null +++ b/test/specs/base/common.js @@ -0,0 +1,10 @@ +class Common { + constructor() { + this.loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.'; + this.ecceIpsum = 'Snare hope zarathustra pious society. Ascetic ocean snare chaos endless war ultimate insofar right god spirit. Right free pinnacle philosophy overcome self philosophy. Right passion value dead truth faithful deceptions. Marvelous hatred derive superiority deceptions justice overcome oneself zarathustra gains.'; + this.bestNotesLink = 'http://bestnotes.pythonanywhere.com/bestnotes/'; + } + +} + +module.exports = new Common(); \ No newline at end of file diff --git a/test/specs/base/navigation.js b/test/specs/base/navigation.js new file mode 100644 index 0000000..e4143f1 --- /dev/null +++ b/test/specs/base/navigation.js @@ -0,0 +1,14 @@ +const base = require('./base'); +const Login = require('../components/login'); + +class Navigation { + constructor() { + this.loginUrl = 'http://bestnotes.pythonanywhere.com/bestnotes/accounts/login/'; + } + + toLoginPage() { + browser.url(this.loginUrl); + return new Login(); + } +} +module.exports = new Navigation(); diff --git a/test/specs/components/login.js b/test/specs/components/login.js new file mode 100644 index 0000000..77de129 --- /dev/null +++ b/test/specs/components/login.js @@ -0,0 +1,15 @@ +const path = require('path'); +const base = require('../base/base'); + +class Login { + constructor() { + this.loginForm = '.login-form-2'; + } + + isLoginFormDisplayed() { + base.waitForDisplayed(this.loginForm); + return base.isDisplayed(this.loginForm); + } +} + +module.exports = Login; \ No newline at end of file diff --git a/test/specs/suites/desktop/loginpage.test.js b/test/specs/suites/desktop/loginpage.test.js new file mode 100644 index 0000000..f7fb2b0 --- /dev/null +++ b/test/specs/suites/desktop/loginpage.test.js @@ -0,0 +1,17 @@ +const { addStep } = require('@wdio/allure-reporter').default; +const { expect } = require('chai'); + +const common = require('../../base/common'); +const navigate = require('../../base/navigation'); +const Login = require('../../components/login'); + +describe('Login page in BestNotes', () => { + + it('should be displayed', () => { + const login = new Login(); + navigate.toLoginPage(); + expect(login.isLoginFormDisplayed(), 'Login form should be displayed').to.be.true; + }) + + it +}); \ No newline at end of file diff --git a/test/specs/testfile.webdriver.js b/test/specs/testfile.webdriver.js deleted file mode 100644 index cc6037c..0000000 --- a/test/specs/testfile.webdriver.js +++ /dev/null @@ -1,9 +0,0 @@ -const assert = require('assert') - -describe('webdriver.io page', () => { - it('should have the right title', () => { - browser.url('https://webdriver.io') - const title = browser.getTitle() - assert.strictEqual(title, 'WebdriverIO ยท Next-gen WebDriver test framework for Node.js') - }) -}) \ No newline at end of file