Commit 951eb70b authored by Marcel Hoyer's avatar Marcel Hoyer Committed by Colin Eberhardt

Correcting asynchronous testing

removes unnecessary .then() chaining in test.js as selenium-webdriver already queues calls internally

fixed confusing inverted use of idSelector variable

promisified all tests

promisified test.launchBrowser() and global test hooks

promisified test.closeBrowser()

promisified test.createStandardItems()

🛀 streamlined testOps to always return the promise and flattened out the thens

fixed testOps.assertClearCompleteButtonText() to wait for visible clear-complete button before asserting

fixed testOps.assertClearCompleteButtonIsVisible() to lazy wait for visible clear-complete button

renamed testOps.assertFocussedElementId() to .assertFocussedElement() and streamlined code

fixed page.clickMarkAllCompletedCheckBox() to return inner promise

fixed page.enterItem() to return the promise and flattened out the thens

renamed page.getFocussedElementName() with .getFocussedElementIdOrClass()

fixed page.ensureAppIsVisible() to wait for 'new-todo' element instead of 'main' as some frameworks build the contents after DOM-ready

fixed page.clickClearCompleteButton() to wait for actual button to display before clicking

extracted page.waitForVisibleElement() helper function
parent 4de8afb2
'use strict'; 'use strict';
var webdriver = require('selenium-webdriver'); var webdriver = require('selenium-webdriver');
var idSelectors = false; var idSelectors = true;
module.exports = function Page(browser) { module.exports = function Page(browser) {
...@@ -16,35 +16,35 @@ module.exports = function Page(browser) { ...@@ -16,35 +16,35 @@ module.exports = function Page(browser) {
}; };
this.getTodoListXpath = function () { this.getTodoListXpath = function () {
return !idSelectors ? '//ul[@id="todo-list"]' : '//ul[contains(@class, "todo-list")]'; return idSelectors ? '//ul[@id="todo-list"]' : '//ul[contains(@class, "todo-list")]';
}; };
this.getMainSectionXpath = function () { this.getMainSectionXpath = function () {
return !idSelectors ? '//section[@id="main"]' : '//section[contains(@class, "main")]'; return idSelectors ? '//section[@id="main"]' : '//section[contains(@class, "main")]';
}; };
this.getFooterSectionXpath = function () { this.getFooterSectionXpath = function () {
return !idSelectors ? '//footer[@id="footer"]' : '//footer[contains(@class, "footer")]'; return idSelectors ? '//footer[@id="footer"]' : '//footer[contains(@class, "footer")]';
}; };
this.getCompletedButtonXpath = function () { this.getCompletedButtonXpath = function () {
return !idSelectors ? '//button[@id="clear-completed"]' : '//button[contains(@class, "clear-completed")]'; return idSelectors ? '//button[@id="clear-completed"]' : '//button[contains(@class, "clear-completed")]';
}; };
this.getNewInputXpath = function () { this.getNewInputXpath = function () {
return !idSelectors ? '//input[@id="new-todo"]' : '//input[contains(@class,"new-todo")]'; return idSelectors ? '//input[@id="new-todo"]' : '//input[contains(@class,"new-todo")]';
}; };
this.getToggleAllXpath = function () { this.getToggleAllXpath = function () {
return !idSelectors ? '//input[@id="toggle-all"]' : '//input[contains(@class,"toggle-all")]'; return idSelectors ? '//input[@id="toggle-all"]' : '//input[contains(@class,"toggle-all")]';
}; };
this.getCountXpath = function () { this.getCountXpath = function () {
return !idSelectors ? '//span[@id="todo-count"]' : '//span[contains(@class, "todo-count")]'; return idSelectors ? '//span[@id="todo-count"]' : '//span[contains(@class, "todo-count")]';
}; };
this.getFiltersElementXpath = function () { this.getFiltersElementXpath = function () {
return !idSelectors ? '//*[@id="filters"]' : '//*[contains(@class, "filters")]'; return idSelectors ? '//*[@id="filters"]' : '//*[contains(@class, "filters")]';
}; };
this.getFilterXpathByIndex = function (index) { this.getFilterXpathByIndex = function (index) {
...@@ -115,9 +115,9 @@ module.exports = function Page(browser) { ...@@ -115,9 +115,9 @@ module.exports = function Page(browser) {
return this.getActiveElement().getTagName(); return this.getActiveElement().getTagName();
}; };
this.getFocussedElementName = function () { this.getFocussedElementIdOrClass = function () {
return this.getActiveElement() return this.getActiveElement()
.getAttribute(!idSelectors ? 'id' : 'class'); .getAttribute(idSelectors ? 'id' : 'class');
}; };
this.getEditInputForItemAtIndex = function (index) { this.getEditInputForItemAtIndex = function (index) {
...@@ -175,9 +175,24 @@ module.exports = function Page(browser) { ...@@ -175,9 +175,24 @@ module.exports = function Page(browser) {
}); });
}; };
this.waitForVisibleElement = function (getElementFn, timeout) {
var foundVisibleElement;
timeout = timeout || 500;
return browser.wait(function () {
foundVisibleElement = getElementFn();
return foundVisibleElement.isDisplayed();
}, timeout)
.then(function () {
return foundVisibleElement;
})
.thenCatch(function (err) {
return false;
});
}
this.getVisibileLabelIndicies = function () { this.getVisibileLabelIndicies = function () {
var self = this; var self = this;
var ret;
return this.getItemLabels() return this.getItemLabels()
.then(function (elms) { .then(function (elms) {
return elms.map(function (elm, i) { return elms.map(function (elm, i) {
...@@ -186,18 +201,8 @@ module.exports = function Page(browser) { ...@@ -186,18 +201,8 @@ module.exports = function Page(browser) {
}) })
.then(function (elms) { .then(function (elms) {
return webdriver.promise.filter(elms, function (elmIndex) { return webdriver.promise.filter(elms, function (elmIndex) {
return browser.wait(function () { return self.waitForVisibleElement(function () {
return self.tryGetItemLabelAtIndex(elmIndex).isDisplayed() return self.tryGetItemLabelAtIndex(elmIndex);
.then(function (v) {
ret = v;
return true;
})
.thenCatch(function () {
return false;
});
}, 5000)
.then(function () {
return ret;
}); });
}); });
}); });
...@@ -205,51 +210,57 @@ module.exports = function Page(browser) { ...@@ -205,51 +210,57 @@ module.exports = function Page(browser) {
// ----------------- page actions // ----------------- page actions
this.ensureAppIsVisible = function () { this.ensureAppIsVisible = function () {
return browser.findElements(webdriver.By.css('#todoapp')) var self = this;
.then(function (elms) { return browser.wait(function () {
if (elms.length > 0) { // try to find main element by ID
return true; return browser.isElementPresent(webdriver.By.css('.new-todo'))
} else { .then(function (foundByClass) {
return browser.findElements(webdriver.By.css('.todoapp')); if (foundByClass) {
} idSelectors = false;
})
.then(function (elms) {
if (elms === true) {
return true; return true;
} }
if (elms.length) { // try to find main element by CSS class
idSelectors = true; return browser.isElementPresent(webdriver.By.css('#new-todo'));
return true; });
}, 5000)
.then(function (hasFoundNewTodoElement) {
if (!hasFoundNewTodoElement) {
throw new Error('Unable to find application, did you start your local server?');
} }
throw new Error('Unable to find application root, did you start your local server?');
}); });
}; };
this.clickMarkAllCompletedCheckBox = function () { this.clickMarkAllCompletedCheckBox = function () {
return this.getMarkAllCompletedCheckBox().then(function (checkbox) { return this.getMarkAllCompletedCheckBox().then(function (checkbox) {
checkbox.click(); return checkbox.click();
}); });
}; };
this.clickClearCompleteButton = function () { this.clickClearCompleteButton = function () {
return this.tryGetClearCompleteButton().click(); var self = this;
return self.waitForVisibleElement(function () {
return self.tryGetClearCompleteButton();
})
.then(function (clearCompleteButton) {
return clearCompleteButton.click();
});
}; };
this.enterItem = function (itemText) { this.enterItem = function (itemText) {
var self = this; var self = this;
browser.wait(function () { return browser.wait(function () {
return self.getItemInputField().then(function (textField) { var textField;
return textField.sendKeys(itemText, webdriver.Key.ENTER)
.then(function () { return self.getItemInputField().then(function (itemInputField) {
return textField; textField = itemInputField;
}); return textField.sendKeys(itemText, webdriver.Key.ENTER);
}).then(function (textField) { })
return self.getVisibleLabelText() .then(function () { return self.getVisibleLabelText(); })
.then(function (labels) { .then(function (labels) {
if (labels.indexOf(itemText.trim()) !== -1) { if (labels.indexOf(itemText.trim()) >= 0) {
return true; return true;
} }
...@@ -257,7 +268,6 @@ module.exports = function Page(browser) { ...@@ -257,7 +268,6 @@ module.exports = function Page(browser) {
return false; return false;
}); });
}); });
});
}, 5000); }, 5000);
}; };
......
...@@ -15,13 +15,18 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -15,13 +15,18 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
var browser, testOps, page; var browser, testOps, page;
// a number of tests use this set of ToDo items. // a number of tests use this set of ToDo items.
function createStandardItems() { function createStandardItems(done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO); page.enterItem(TODO_ITEM_TWO);
page.enterItem(TODO_ITEM_THREE); return page.enterItem(TODO_ITEM_THREE)
.then(function () {
if (done instanceof Function) {
done();
};
});
} }
function launchBrowser() { function launchBrowser(done) {
var chromeOptions = new chrome.Options(); var chromeOptions = new chrome.Options();
chromeOptions.addArguments('no-sandbox'); chromeOptions.addArguments('no-sandbox');
...@@ -30,9 +35,7 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -30,9 +35,7 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
} }
browser = new webdriver.Builder() browser = new webdriver.Builder()
.withCapabilities({ .withCapabilities({browserName: browserName})
browserName: browserName
})
.setChromeOptions(chromeOptions) .setChromeOptions(chromeOptions)
.build(); .build();
...@@ -41,135 +44,153 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -41,135 +44,153 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
page = laxMode ? new PageLaxMode(browser) : new Page(browser); page = laxMode ? new PageLaxMode(browser) : new Page(browser);
testOps = new TestOperations(page); testOps = new TestOperations(page);
// for apps that use require, we have to wait a while for the dependencies to return page.ensureAppIsVisible()
// be loaded. There must be a more elegant solution than this! .then(function () {
browser.sleep(200); if (done instanceof Function) {
done();
};
});
} }
function closeBrowser() { function printCapturedLogs() {
browser.quit(); var logs = new webdriver.WebDriver.Logs(browser);
}
if (speedMode) { return logs.get('browser')
test.before(function () { .then(function (entries) {
launchBrowser(); if (entries && entries.length) {
console.log(entries);
}
}); });
test.after(function () { }
closeBrowser();
function closeBrowser(done) {
return browser
.quit()
.then(function () {
if (done instanceof Function) {
done();
};
}); });
test.beforeEach(function () { }
page.getItemElements().then(function (items) {
if (items.length > 0) { if (speedMode) {
test.before(launchBrowser);
test.after(closeBrowser);
test.beforeEach(function (done) {
return page.getItemElements()
.then(function (items) {
if (items.length == 0) { return; }
// find any items that are not complete // find any items that are not complete
page.getNonCompletedItemElements().then(function (nonCompleteItems) { page.getNonCompletedItemElements()
.then(function (nonCompleteItems) {
if (nonCompleteItems.length > 0) { if (nonCompleteItems.length > 0) {
page.clickMarkAllCompletedCheckBox(); return page.clickMarkAllCompletedCheckBox();
} }
page.clickClearCompleteButton(); })
});
} return page.clickClearCompleteButton();
}); })
.then(function () { done(); });
}); });
} else { } else {
test.beforeEach(function () { test.beforeEach(launchBrowser);
launchBrowser(); test.afterEach(function (done) {
page.ensureAppIsVisible(); printCapturedLogs()
}); .then(function () {
test.afterEach(function () { return closeBrowser(done);
(new webdriver.WebDriver.Logs(browser)) })
.get('browser')
.then(function (v) {
if (v && v.length) {
console.log(v);
}
});
closeBrowser();
}); });
} }
test.describe('When page is initially opened', function () { test.describe('When page is initially opened', function () {
test.it('should focus on the todo input field', function () { test.it('should focus on the todo input field', function (done) {
testOps.assertFocussedElementId('new-todo'); testOps.assertFocussedElement('new-todo')
.then(function () { done(); });
}); });
}); });
test.describe('No Todos', function () { test.describe('No Todos', function () {
test.it('should hide #main and #footer', function () { test.it('should hide #main and #footer', function (done) {
testOps.assertItemCount(0); testOps.assertItemCount(0);
testOps.assertMainSectionIsHidden(); testOps.assertMainSectionIsHidden();
testOps.assertFooterIsHidden(); testOps.assertFooterIsHidden()
.then(function () { done(); });
}); });
}); });
test.describe('New Todo', function () { test.describe('New Todo', function () {
test.it('should allow me to add todo items', function () { test.it('should allow me to add todo items', function (done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
testOps.assertItems([TODO_ITEM_ONE]); testOps.assertItems([TODO_ITEM_ONE]);
page.enterItem(TODO_ITEM_TWO); page.enterItem(TODO_ITEM_TWO);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO]); testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO])
.then(function () { done(); });
}); });
test.it('should clear text input field when an item is added', function () { test.it('should clear text input field when an item is added', function (done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
testOps.assertItemInputFieldText(''); testOps.assertItemInputFieldText('')
.then(function () { done(); });
}); });
test.it('should append new items to the bottom of the list', function () { test.it('should append new items to the bottom of the list', function (done) {
createStandardItems(); createStandardItems();
testOps.assertItemCount(3); testOps.assertItemCount(3);
testOps.assertItemText(0, TODO_ITEM_ONE); testOps.assertItemText(0, TODO_ITEM_ONE);
testOps.assertItemText(1, TODO_ITEM_TWO); testOps.assertItemText(1, TODO_ITEM_TWO);
testOps.assertItemText(2, TODO_ITEM_THREE); testOps.assertItemText(2, TODO_ITEM_THREE)
.then(function () { done(); });
}); });
test.it('should trim text input', function () { test.it('should trim text input', function (done) {
page.enterItem(' ' + TODO_ITEM_ONE + ' '); page.enterItem(' ' + TODO_ITEM_ONE + ' ');
testOps.assertItemText(0, TODO_ITEM_ONE); testOps.assertItemText(0, TODO_ITEM_ONE)
.then(function () { done(); });
}); });
test.it('should show #main and #footer when items added', function () { test.it('should show #main and #footer when items added', function (done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
testOps.assertMainSectionIsVisible(); testOps.assertMainSectionIsVisible();
testOps.assertFooterIsVisible(); testOps.assertFooterIsVisible()
.then(function () { done(); });
}); });
}); });
test.describe('Mark all as completed', function () { test.describe('Mark all as completed', function () {
test.beforeEach(function () { test.beforeEach(createStandardItems);
createStandardItems();
});
test.it('should allow me to mark all items as completed', function () { test.it('should allow me to mark all items as completed', function (done) {
page.clickMarkAllCompletedCheckBox(); page.clickMarkAllCompletedCheckBox();
testOps.assertItemAtIndexIsCompleted(0); testOps.assertItemAtIndexIsCompleted(0);
testOps.assertItemAtIndexIsCompleted(1); testOps.assertItemAtIndexIsCompleted(1);
testOps.assertItemAtIndexIsCompleted(2); testOps.assertItemAtIndexIsCompleted(2)
.then(function () { done(); });
}); });
test.it('should correctly update the complete all checked state', function () { test.it('should correctly update the complete all checked state', function (done) {
// manually check all items // manually check all items
page.toggleItemAtIndex(0); page.toggleItemAtIndex(0);
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
page.toggleItemAtIndex(2); page.toggleItemAtIndex(2);
// ensure checkall is in the correct state // ensure checkall is in the correct state
testOps.assertCompleteAllIsChecked(); testOps.assertCompleteAllIsChecked()
.then(function () { done(); });
}); });
test.it('should allow me to clear the completion state of all items', function () { test.it('should allow me to clear the completion state of all items', function (done) {
page.clickMarkAllCompletedCheckBox(); page.clickMarkAllCompletedCheckBox();
page.clickMarkAllCompletedCheckBox(); page.clickMarkAllCompletedCheckBox();
testOps.assertItemAtIndexIsNotCompleted(0); testOps.assertItemAtIndexIsNotCompleted(0);
testOps.assertItemAtIndexIsNotCompleted(1); testOps.assertItemAtIndexIsNotCompleted(1);
testOps.assertItemAtIndexIsNotCompleted(2); testOps.assertItemAtIndexIsNotCompleted(2)
.then(function () { done(); });
}); });
test.it('complete all checkbox should update state when items are completed / cleared', function () { test.it('complete all checkbox should update state when items are completed / cleared', function (done) {
page.clickMarkAllCompletedCheckBox(); page.clickMarkAllCompletedCheckBox();
testOps.assertCompleteAllIsChecked(); testOps.assertCompleteAllIsChecked();
// all items are complete, now mark one as not-complete // all items are complete, now mark one as not-complete
...@@ -178,12 +199,13 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -178,12 +199,13 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
// now mark as complete, so that once again all items are completed // now mark as complete, so that once again all items are completed
page.toggleItemAtIndex(0); page.toggleItemAtIndex(0);
testOps.assertCompleteAllIsChecked(); testOps.assertCompleteAllIsChecked()
.then(function () { done(); });
}); });
}); });
test.describe('Item', function () { test.describe('Item', function () {
test.it('should allow me to mark items as complete', function () { test.it('should allow me to mark items as complete', function (done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO); page.enterItem(TODO_ITEM_TWO);
...@@ -193,10 +215,11 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -193,10 +215,11 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
testOps.assertItemAtIndexIsCompleted(0); testOps.assertItemAtIndexIsCompleted(0);
testOps.assertItemAtIndexIsCompleted(1); testOps.assertItemAtIndexIsCompleted(1)
.then(function () { done(); });
}); });
test.it('should allow me to un-mark items as complete', function () { test.it('should allow me to un-mark items as complete', function (done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO); page.enterItem(TODO_ITEM_TWO);
...@@ -206,102 +229,101 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -206,102 +229,101 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
page.toggleItemAtIndex(0); page.toggleItemAtIndex(0);
testOps.assertItemAtIndexIsNotCompleted(0); testOps.assertItemAtIndexIsNotCompleted(0);
testOps.assertItemAtIndexIsNotCompleted(1); testOps.assertItemAtIndexIsNotCompleted(1)
.then(function () { done(); });
}); });
}); });
test.describe('Editing', function () { test.describe('Editing', function (done) {
test.beforeEach(function () { test.beforeEach(function (done) {
createStandardItems(); createStandardItems();
page.doubleClickItemAtIndex(1); page.doubleClickItemAtIndex(1)
.then(function () { done(); });
}); });
test.it('should focus the input', function () { test.it('should focus the input', function (done) {
testOps.assertInputFocused(); testOps.assertInputFocused();
testOps.assertNewInputNotFocused(); testOps.assertNewInputNotFocused()
.then(function () { done(); });
}); });
test.it('should hide other controls when editing', function () { test.it('should hide other controls when editing', function (done) {
testOps.assertItemToggleIsHidden(1); testOps.assertItemToggleIsHidden(1);
testOps.assertItemLabelIsHidden(1); testOps.assertItemLabelIsHidden(1)
.then(function () { done(); });
}); });
test.it('should save edits on enter', function () { test.it('should save edits on enter', function (done) {
page.editItemAtIndex(1, 'buy some sausages' + webdriver.Key.ENTER); page.editItemAtIndex(1, 'buy some sausages' + webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]); .then(function () { done(); });
}); });
test.it('should save edits on blur', function () { test.it('should save edits on blur', function (done) {
page.editItemAtIndex(1, 'buy some sausages'); page.editItemAtIndex(1, 'buy some sausages');
// click a toggle button so that the blur() event is fired // click a toggle button so that the blur() event is fired
page.toggleItemAtIndex(0); page.toggleItemAtIndex(0);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]); .then(function () { done(); });
}); });
test.it('should trim entered text', function () { test.it('should trim entered text', function (done) {
page.editItemAtIndex(1, ' buy some sausages ' + webdriver.Key.ENTER); page.editItemAtIndex(1, ' buy some sausages ' + webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]); .then(function () { done(); });
}); });
test.it('should remove the item if an empty text string was entered', function () { test.it('should remove the item if an empty text string was entered', function (done) {
page.editItemAtIndex(1, webdriver.Key.ENTER); page.editItemAtIndex(1, webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]); .then(function () { done(); });
}); });
test.it('should cancel edits on escape', function () { test.it('should cancel edits on escape', function (done) {
page.editItemAtIndex(1, 'foo' + webdriver.Key.ESCAPE); page.editItemAtIndex(1, 'foo' + webdriver.Key.ESCAPE);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE]); .then(function () { done(); });
}); });
}); });
test.describe('Counter', function () { test.describe('Counter', function () {
test.it('should display the current number of todo items', function () { test.it('should display the current number of todo items', function (done) {
page.enterItem(TODO_ITEM_ONE); page.enterItem(TODO_ITEM_ONE);
testOps.assertItemCountText('1 item left'); testOps.assertItemCountText('1 item left');
page.enterItem(TODO_ITEM_TWO); page.enterItem(TODO_ITEM_TWO);
testOps.assertItemCountText('2 items left'); testOps.assertItemCountText('2 items left')
.then(function () { done(); });
}); });
}); });
test.describe('Clear completed button', function () { test.describe('Clear completed button', function () {
test.beforeEach(function () { test.beforeEach(createStandardItems);
createStandardItems();
});
test.it('should display the correct text', function () { test.it('should display the correct text', function (done) {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
testOps.assertClearCompleteButtonText('Clear completed'); testOps.assertClearCompleteButtonText('Clear completed')
.then(function () { done(); });
}); });
test.it('should remove completed items when clicked', function () { test.it('should remove completed items when clicked', function (done) {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
page.clickClearCompleteButton(); page.clickClearCompleteButton();
testOps.assertItemCount(2); testOps.assertItemCount(2);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]); testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE])
.then(function () { done(); });
}); });
test.it('should be hidden when there are no items that are completed', function () { test.it('should be hidden when there are no items that are completed', function (done) {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
testOps.assertClearCompleteButtonIsVisible(); testOps.assertClearCompleteButtonIsVisible();
page.clickClearCompleteButton(); page.clickClearCompleteButton();
testOps.assertClearCompleteButtonIsHidden(); testOps.assertClearCompleteButtonIsHidden()
.then(function () { done(); });
}); });
}); });
test.describe('Persistence', function () { test.describe('Persistence', function () {
test.it('should persist its data', function () { test.it('should persist its data', function (done) {
// set up state
page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO);
page.toggleItemAtIndex(1);
function stateTest() { function stateTest() {
// wait until things are visible // wait until things are visible
browser.wait(function () { browser.wait(function () {
...@@ -309,13 +331,16 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -309,13 +331,16 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
return labels.length > 0; return labels.length > 0;
}); });
}, 5000); }, 5000);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO]); testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO]);
testOps.assertItemAtIndexIsCompleted(1); testOps.assertItemAtIndexIsCompleted(1);
testOps.assertItemAtIndexIsNotCompleted(0);
return testOps.assertItemAtIndexIsNotCompleted(0);
} }
// test it // set up state
page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO);
page.toggleItemAtIndex(1);
stateTest(); stateTest();
// navigate away and back again // navigate away and back again
...@@ -323,66 +348,60 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod ...@@ -323,66 +348,60 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod
browser.get(baseUrl); browser.get(baseUrl);
// repeat the state test // repeat the state test
stateTest(); stateTest()
.then(function () { done(); });
}); });
}); });
test.describe('Routing', function () { test.describe('Routing', function () {
test.beforeEach(function () { test.beforeEach(createStandardItems);
createStandardItems();
}); test.it('should allow me to display active items', function (done) {
test.it('should allow me to display active items', function () {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
page.filterByActiveItems(); page.filterByActiveItems();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]); .then(function () { return done(); });
}); });
test.it('should respect the back button', function () { test.it('should respect the back button', function (done) {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
page.filterByActiveItems(); page.filterByActiveItems();
page.filterByCompletedItems(); page.filterByCompletedItems();
testOps.assertItems([TODO_ITEM_TWO]);// should show completed items
// should show completed items page.back(); // then active items
testOps.assertItems([TODO_ITEM_TWO]);
// then active items
page.back();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]); testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]);
page.back(); // then all items
// then all items testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE])
page.back(); .then(function () { done(); });
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE]);
}); });
test.it('should allow me to display completed items', function () { test.it('should allow me to display completed items', function (done) {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
page.filterByCompletedItems(); page.filterByCompletedItems();
testOps.assertItems([TODO_ITEM_TWO]); testOps.assertItems([TODO_ITEM_TWO]);
page.filterByAllItems() // TODO: why
.then(function () { done(); });
}); });
test.it('should allow me to display all items', function () { test.it('should allow me to display all items', function (done) {
page.toggleItemAtIndex(1); page.toggleItemAtIndex(1);
// apply the other filters first, before returning to the 'all' state // apply the other filters first, before returning to the 'all' state
page.filterByActiveItems(); page.filterByActiveItems();
page.filterByCompletedItems(); page.filterByCompletedItems();
page.filterByAllItems(); page.filterByAllItems();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE])
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE]); .then(function () { done(); });
}); });
test.it('should highlight the currently applied filter', function () { test.it('should highlight the currently applied filter', function (done) {
// initially 'all' should be selected // initially 'all' should be selected
testOps.assertFilterAtIndexIsSelected(0); testOps.assertFilterAtIndexIsSelected(0);
page.filterByActiveItems(); page.filterByActiveItems();
testOps.assertFilterAtIndexIsSelected(1); testOps.assertFilterAtIndexIsSelected(1);
page.filterByCompletedItems(); page.filterByCompletedItems();
testOps.assertFilterAtIndexIsSelected(2); testOps.assertFilterAtIndexIsSelected(2)
.then(function () { done(); });
}); });
}); });
}); });
......
...@@ -16,15 +16,16 @@ function TestOperations(page) { ...@@ -16,15 +16,16 @@ function TestOperations(page) {
function testIsVisible(elements, name) { function testIsVisible(elements, name) {
assert.equal(elements.length, 1); assert.equal(elements.length, 1);
elements[0].isDisplayed().then(function (isDisplayed) { return elements[0].isDisplayed()
.then(function (isDisplayed) {
assert(isDisplayed, 'the ' + name + ' element should be displayed'); assert(isDisplayed, 'the ' + name + ' element should be displayed');
}); });
} }
this.assertNewInputNotFocused = function () { this.assertNewInputNotFocused = function () {
return page.getFocussedElementName() return page.getFocussedElementIdOrClass()
.then(function (name) { .then(function (focussedElementIdOrClass) {
assert.notEqual(name, 'new-todo'); assert.equal(focussedElementIdOrClass.indexOf('new-todo'), -1);
}); });
}; };
...@@ -35,85 +36,105 @@ function TestOperations(page) { ...@@ -35,85 +36,105 @@ function TestOperations(page) {
}); });
}; };
this.assertFocussedElementId = function (expectedId) { this.assertFocussedElement = function (expectedIdentifier) {
page.getFocussedElementName().then(function (id) { return page.getFocussedElementIdOrClass()
assert.notEqual(id.indexOf(expectedId), -1, 'The focused element did not have the expected id ' + expectedId); .then(function (focusedElementIdentifier) {
var failMsg = 'The focused element did not have the expected class or id "' + expectedIdentifier + '"';
assert.notEqual(focusedElementIdentifier.indexOf(expectedIdentifier), -1, failMsg);
}); });
}; };
this.assertClearCompleteButtonIsHidden = function () { this.assertClearCompleteButtonIsHidden = function () {
page.tryGetClearCompleteButton().then(function (element) { return page.tryGetClearCompleteButton()
testIsHidden(element, 'clear completed items button'); .then(function (element) {
return testIsHidden(element, 'clear completed items button');
}, function (_error) { }, function (_error) {
assert(_error.code === 7, 'error accessing clear completed items button, error: ' + _error.message); assert(_error.code === 7, 'error accessing clear completed items button, error: ' + _error.message);
}); });
}; };
this.assertClearCompleteButtonIsVisible = function () { this.assertClearCompleteButtonIsVisible = function () {
page.tryGetClearCompleteButton().then(function (element) { return page.waitForVisibleElement(function () {
testIsVisible([element], 'clear completed items button'); return page.tryGetClearCompleteButton();
})
.then(function (clearCompleteButton) {
assert(clearCompleteButton, 'the clear completed items button element should be displayed');
}); });
}; };
this.assertItemCount = function (itemCount) { this.assertItemCount = function (itemCount) {
page.getItemElements().then(function (toDoItems) { return page.getItemElements()
.then(function (toDoItems) {
assert.equal(toDoItems.length, itemCount, assert.equal(toDoItems.length, itemCount,
itemCount + ' items expected in the todo list, ' + toDoItems.length + ' items observed'); itemCount + ' items expected in the todo list, ' + toDoItems.length + ' items observed');
}); });
}; };
this.assertClearCompleteButtonText = function (buttonText) { this.assertClearCompleteButtonText = function (buttonText) {
return page.tryGetClearCompleteButton() return page.waitForVisibleElement(function () {
.getText().then(function (text) { return page.tryGetClearCompleteButton();
assert.equal(text, buttonText); })
.then(function (clearCompleteButton) {
return clearCompleteButton.getText();
})
.then(function (text) {
return assert.equal(text, buttonText);
}); });
}; };
this.assertMainSectionIsHidden = function () { this.assertMainSectionIsHidden = function () {
page.tryGetMainSectionElement().then(function (mainSection) { return page.tryGetMainSectionElement()
testIsHidden(mainSection, 'main'); .then(function (mainSection) {
return testIsHidden(mainSection, 'main');
}); });
}; };
this.assertFooterIsHidden = function () { this.assertFooterIsHidden = function () {
page.tryGetFooterElement().then(function (footer) { return page.tryGetFooterElement()
testIsHidden(footer, 'footer'); .then(function (footer) {
return testIsHidden(footer, 'footer');
}); });
}; };
this.assertMainSectionIsVisible = function () { this.assertMainSectionIsVisible = function () {
page.tryGetMainSectionElement().then(function (mainSection) { return page.tryGetMainSectionElement()
testIsVisible(mainSection, 'main'); .then(function (mainSection) {
return testIsVisible(mainSection, 'main');
}); });
}; };
//TODO: fishy! //TODO: fishy!
this.assertItemToggleIsHidden = function (index) { this.assertItemToggleIsHidden = function (index) {
page.tryGetToggleForItemAtIndex(index).then(function (toggleItem) { return page.tryGetToggleForItemAtIndex(index)
testIsHidden(toggleItem, 'item-toggle'); .then(function (toggleItem) {
return testIsHidden(toggleItem, 'item-toggle');
}); });
}; };
this.assertItemLabelIsHidden = function (index) { this.assertItemLabelIsHidden = function (index) {
page.tryGetItemLabelAtIndex(index).then(function (toggleItem) { return page.tryGetItemLabelAtIndex(index)
testIsHidden(toggleItem, 'item-label'); .then(function (toggleItem) {
return testIsHidden(toggleItem, 'item-label');
}); });
}; };
this.assertFooterIsVisible = function () { this.assertFooterIsVisible = function () {
page.tryGetFooterElement().then(function (footer) { return page.tryGetFooterElement()
testIsVisible(footer, 'footer'); .then(function (footer) {
return testIsVisible(footer, 'footer');
}); });
}; };
this.assertItemInputFieldText = function (text) { this.assertItemInputFieldText = function (text) {
page.getItemInputField().getText().then(function (inputFieldText) { return page.getItemInputField().getText()
.then(function (inputFieldText) {
assert.equal(inputFieldText, text); assert.equal(inputFieldText, text);
}); });
}; };
this.assertItemText = function (itemIndex, textToAssert) { this.assertItemText = function (itemIndex, textToAssert) {
page.getItemLabelAtIndex(itemIndex).getText().then(function (text) { return page.getItemLabelAtIndex(itemIndex).getText()
.then(function (text) {
assert.equal(text, textToAssert, assert.equal(text, textToAssert,
'A todo item with text \'' + textToAssert + '\' was expected at index ' + 'A todo item with text \'' + textToAssert + '\' was expected at index ' +
itemIndex + ', the text \'' + text + '\' was observed'); itemIndex + ', the text \'' + text + '\' was observed');
...@@ -129,53 +150,63 @@ function TestOperations(page) { ...@@ -129,53 +150,63 @@ function TestOperations(page) {
}; };
this.assertItemCountText = function (textToAssert) { this.assertItemCountText = function (textToAssert) {
page.getItemsCountElement().getText().then(function (text) { return page.getItemsCountElement().getText()
.then(function (text) {
assert.equal(text.trim(), textToAssert, 'the item count text was incorrect'); assert.equal(text.trim(), textToAssert, 'the item count text was incorrect');
}); });
}; };
// tests for the presence of the 'completed' CSS class for the item at the given index // tests for the presence of the 'completed' CSS class for the item at the given index
this.assertItemAtIndexIsCompleted = function (index) { this.assertItemAtIndexIsCompleted = function (index) {
page.getItemElements().then(function (toDoItems) { return page.getItemElements()
toDoItems[index].getAttribute('class').then(function (cssClass) { .then(function (toDoItems) {
assert(cssClass.indexOf('completed') !== -1, return toDoItems[index].getAttribute('class');
'the item at index ' + index + ' should have been marked as completed'); })
}); .then(function (cssClass) {
var failMsg = 'the item at index ' + index + ' should have been marked as completed';
assert(cssClass.indexOf('completed') !== -1, failMsg);
}); });
}; };
this.assertItemAtIndexIsNotCompleted = function (index) { this.assertItemAtIndexIsNotCompleted = function (index) {
page.getItemElements().then(function (toDoItems) { return page.getItemElements()
toDoItems[index].getAttribute('class').then(function (cssClass) { .then(function (toDoItems) {
return toDoItems[index].getAttribute('class');
})
.then(function (cssClass) {
// the maria implementation uses an 'incompleted' CSS class which is redundant // the maria implementation uses an 'incompleted' CSS class which is redundant
// TODO: this should really be moved into the pageLaxMode // TODO: this should really be moved into the pageLaxMode
assert(cssClass.indexOf('completed') === -1 || cssClass.indexOf('incompleted') !== -1, var failMsg = 'the item at index ' + index + ' should not have been marked as completed';
'the item at index ' + index + ' should not have been marked as completed'); assert(cssClass.indexOf('completed') === -1 || cssClass.indexOf('incompleted') !== -1, failMsg);
});
}); });
}; };
this.assertFilterAtIndexIsSelected = function (selectedIndex) { this.assertFilterAtIndexIsSelected = function (selectedIndex) {
page.findByXpath(page.getSelectedFilterXPathByIndex(selectedIndex + 1)) return page.findByXpath(page.getSelectedFilterXPathByIndex(selectedIndex + 1))
.then(function (elm) { .then(function (elm) {
assert.notEqual(elm, undefined, 'the filter / route at index ' + selectedIndex + ' should have been selected'); var failMsg = 'the filter / route at index ' + selectedIndex + ' should have been selected';
assert.notEqual(elm, undefined, failMsg);
}); });
}; };
this.assertCompleteAllIsClear = function () { this.assertCompleteAllIsClear = function () {
page.getMarkAllCompletedCheckBox().then(function (markAllCompleted) { return page.getMarkAllCompletedCheckBox()
markAllCompleted.isSelected().then(function (isSelected) { .then(function (markAllCompleted) {
return markAllCompleted.isSelected();
})
.then(function (isSelected) {
assert(!isSelected, 'the mark-all-completed checkbox should be clear'); assert(!isSelected, 'the mark-all-completed checkbox should be clear');
}); });
});
}; };
this.assertCompleteAllIsChecked = function () { this.assertCompleteAllIsChecked = function () {
page.getMarkAllCompletedCheckBox().then(function (markAllCompleted) { return page.getMarkAllCompletedCheckBox()
markAllCompleted.isSelected().then(function (isSelected) { .then(function (markAllCompleted) {
return markAllCompleted.isSelected();
})
.then(function (isSelected) {
assert(isSelected, 'the mark-all-completed checkbox should be checked'); assert(isSelected, 'the mark-all-completed checkbox should be checked');
}); });
});
}; };
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment