From 140d6f6bb14eff8cd0d75fae08c485f09c2f7874 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Sun, 2 Feb 2014 20:14:44 +0000 Subject: [PATCH] Further work in 'lax mode' I have executed all 1708 tests and made a first pass at recording the known issues. I have also made quite a few changes to the 'lax mode' path expressions. It is going to take a few iterations to find the expressions that work for all the different apps! I have also temporarily disabled the persistence test, it fails intermitently at the moment. --- browser-tests/allTests.js | 14 ++++- browser-tests/knownIssues.js | 100 ++++++++++++++++++++++++++++++++ browser-tests/page.js | 43 +++++++++----- browser-tests/pageLaxMode.js | 32 +++++++++- browser-tests/test.js | 4 +- browser-tests/testOperations.js | 2 +- 6 files changed, 175 insertions(+), 20 deletions(-) diff --git a/browser-tests/allTests.js b/browser-tests/allTests.js index 06a2cd7592..d46cac63d5 100644 --- a/browser-tests/allTests.js +++ b/browser-tests/allTests.js @@ -10,6 +10,15 @@ var frameworkNamePattern = /^[a-z-_]+$/; // not worth testing via a generic mecanism var excludedFrameworks = ['gwt', 'polymer']; +// these implementations cannot be run offline, because they are hosted +excludedFrameworks = excludedFrameworks.concat(['derby', 'firebase-angular', 'meteor', 'socketstream', + // YUI is a special case here, it is not hosted, but fetches JS files dynamically + 'yui', + // these frameworks take a long time to start-up, and there is no easy way to determine when they are ready + 'cujo', 'montage', + // this example has been removed (see the readme in the framework folder) + 'emberjs_require']); + // collect together the framework names from each of the subfolders var list = fs.readdirSync('../architecture-examples/') .map(function (folderName) { @@ -33,7 +42,10 @@ var list = fs.readdirSync('../architecture-examples/') // apps that are not hosted at the root of their folder need to be handled explicitly var exceptions = [ - { name: 'chaplin-brunch', path: 'labs/dependency-examples/chaplin-brunch/public' } + { name: 'chaplin-brunch', path: 'labs/dependency-examples/chaplin-brunch/public' }, + { name: 'angular-dart', path: 'labs/architecture-examples/angular-dart/web' }, + { name: 'duel', path: 'labs/architecture-examples/duel/www' }, + { name: 'thorax_lumbar', path: 'labs/dependency-examples/thorax_lumbar/public' }, ]; list = list.map(function (framework) { var exception = exceptions.filter(function (exFramework) { diff --git a/browser-tests/knownIssues.js b/browser-tests/knownIssues.js index 269137e161..eeee4e5a5c 100644 --- a/browser-tests/knownIssues.js +++ b/browser-tests/knownIssues.js @@ -1,4 +1,28 @@ module.exports = [ + + // https://github.com/tastejs/todomvc/issues/815 + // does not hide other controls while editing + 'TodoMVC - dojo, Editing, should hide other controls when editing', + + // https://github.com/tastejs/todomvc/issues/816 + // atma does not hide the main section, instead it hides the toggle-all checkbox + 'TodoMVC - atmajs, No Todos, should hide #main and #footer', + + // https://github.com/tastejs/todomvc/issues/817 + // batman does not trim input + 'TodoMVC - batman, New Todo, should trim text input', + + // https://github.com/tastejs/todomvc/issues/818 + // does not trim edited text + 'TodoMVC - dermis, Editing, should trim entered text', + 'TodoMVC - kendo, Editing, should trim entered text', + 'TodoMVC - serenadejs, Editing, should trim entered text', + + // https://github.com/tastejs/todomvc/issues/819 + // the edit experience with soma is quite broken. You can + // get multiple elements into an edit state + 'TodoMVC - somajs, Editing, should remove the item if an empty text string was entered', + // the following are covered by the following issue: // https://github.com/tastejs/todomvc/issues/789 'TodoMVC - agilityjs, Editing, should cancel edits on escape', @@ -20,6 +44,21 @@ module.exports = [ 'TodoMVC - maria, Routing, should allow me to display completed items', 'TodoMVC - dojo, Routing, should allow me to display active items', 'TodoMVC - dojo, Routing, should allow me to display completed items', + 'TodoMVC - atmajs, Routing, should allow me to display active items', + 'TodoMVC - atmajs, Routing, should allow me to display completed items', + 'TodoMVC - backbone_marionette, Routing, should allow me to display active items', + 'TodoMVC - backbone_marionette, Routing, should allow me to display completed items', + 'TodoMVC - exoskeleton, Routing, should allow me to display active items', + 'TodoMVC - exoskeleton, Routing, should allow me to display completed items', + 'TodoMVC - thorax, Routing, should allow me to display active items', + 'TodoMVC - thorax, Routing, should allow me to display completed items', + 'TodoMVC - thorax_lumbar, Routing, should allow me to display active items', + 'TodoMVC - thorax_lumbar, Routing, should allow me to display completed items', + 'TodoMVC - troopjs_require, Routing, should allow me to display active items', + 'TodoMVC - troopjs_require, Routing, should allow me to display completed items', + 'TodoMVC - backbone_require, Routing, should allow me to display active items', + 'TodoMVC - backbone_require, Routing, should allow me to display completed items', + // the following are covered by this issue: // https://github.com/tastejs/todomvc/issues/795 @@ -31,6 +70,67 @@ module.exports = [ 'TodoMVC - jquery, Routing, should allow me to display completed items', 'TodoMVC - jquery, Routing, should allow me to display all items', 'TodoMVC - jquery, Routing, should highlight the currently applied filter', + 'TodoMVC - extjs_deftjs, Routing, should allow me to display active items', + 'TodoMVC - extjs_deftjs, Routing, should allow me to display completed items', + 'TodoMVC - extjs_deftjs, Routing, should allow me to display all items', + 'TodoMVC - extjs_deftjs, Routing, should highlight the currently applied filter', + 'TodoMVC - olives, Routing, should allow me to display active items', + 'TodoMVC - olives, Routing, should allow me to display completed items', + 'TodoMVC - olives, Routing, should allow me to display all items', + 'TodoMVC - olives, Routing, should highlight the currently applied filter', + 'TodoMVC - dijon, Routing, should allow me to display completed items', + 'TodoMVC - dijon, Routing, should allow me to display all items', + 'TodoMVC - dijon, Routing, should highlight the currently applied filter', + 'TodoMVC - duel, Routing, should allow me to display active items', + 'TodoMVC - duel, Routing, should allow me to display completed items', + 'TodoMVC - duel, Routing, should allow me to display all items', + 'TodoMVC - duel, Routing, should highlight the currently applied filter', + 'TodoMVC - knockoutjs_require, Routing, should allow me to display active items', + 'TodoMVC - knockoutjs_require, Routing, should allow me to display completed items', + 'TodoMVC - knockoutjs_require, Routing, should allow me to display all items', + 'TodoMVC - knockoutjs_require, Routing, should highlight the currently applied filter', + + + // EXTJS is not spec compliant (by a long way!) + 'TodoMVC - extjs, New Todo, should show #main and #footer when items added', + 'TodoMVC - extjs, Mark all as completed, should allow me to mark all items as completed', + 'TodoMVC - extjs, Mark all as completed, complete all checkbox should update state when items are completed / cleared', + 'TodoMVC - extjs, Item, should allow me to mark items as complete', + 'TodoMVC - extjs, Item, should allow me to un-mark items as complete', + 'TodoMVC - extjs, Editing, should save edits on blur', + 'TodoMVC - extjs, Editing, should cancel edits on escape', + 'TodoMVC - extjs, Counter, should display the current number of todo items', + 'TodoMVC - extjs, Clear completed button, should display the number of completed items', + 'TodoMVC - extjs, Clear completed button, should remove completed items when clicked', + 'TodoMVC - extjs, Clear completed button, should be hidden when there are no items that are completed', + 'TodoMVC - extjs, Persistence, should persist its data', + 'TodoMVC - extjs, Routing, should allow me to display active items', + 'TodoMVC - extjs, Routing, should allow me to display completed items', + 'TodoMVC - extjs, Routing, should allow me to display all items', + 'TodoMVC - extjs, Routing, should highlight the currently applied filter', + + // stapes is completely broken! + // see: https://github.com/tastejs/todomvc/issues/808 + 'TodoMVC - stapes, Mark all as completed, should allow me to mark all items as completed', + 'TodoMVC - stapes, Mark all as completed, should allow me to clear the completion state of all items', + 'TodoMVC - stapes, Mark all as completed, complete all checkbox should update state when items are completed / cleared', + 'TodoMVC - stapes, Item, should allow me to mark items as complete', + 'TodoMVC - stapes, Item, should allow me to un-mark items as complete', + 'TodoMVC - stapes, Item, should allow me to edit an item', + 'TodoMVC - stapes, Editing, should hide other controls when editing', + 'TodoMVC - stapes, Editing, should save edits on enter', + 'TodoMVC - stapes, Editing, should save edits on blur', + 'TodoMVC - stapes, Editing, should trim entered text', + 'TodoMVC - stapes, Editing, should remove the item if an empty text string was entered', + 'TodoMVC - stapes, Editing, should cancel edits on escape', + 'TodoMVC - stapes, Counter, should display the current number of todo items', + 'TodoMVC - stapes, Clear completed button, should display the number of completed items', + 'TodoMVC - stapes, Clear completed button, should remove completed items when clicked', + 'TodoMVC - stapes, Clear completed button, should be hidden when there are no items that are completed', + 'TodoMVC - stapes, Persistence, should persist its data', + 'TodoMVC - stapes, Routing, should allow me to display active items', + 'TodoMVC - stapes, Routing, should allow me to display completed items', + 'TodoMVC - stapes, Routing, should allow me to display all items', // ----------------- Test framework issues ----------- diff --git a/browser-tests/page.js b/browser-tests/page.js index bb29e9d519..e1528aa417 100644 --- a/browser-tests/page.js +++ b/browser-tests/page.js @@ -6,9 +6,21 @@ module.exports = function Page(browser) { // ----------------- utility methods + this.tryFindByXpath = function(xpath) { + return browser.findElements(webdriver.By.xpath(xpath)); + } + + this.findByXpath = function(xpath) { + return browser.findElement(webdriver.By.xpath(xpath)); + } + + this.getTodoListXpath = function() { + return '//ul[@id="todo-list"]'; + } + this.xPathForItemAtIndex = function (index) { // why is XPath the only language silly enough to be 1-indexed? - return '//ul[@id="todo-list"]/li[' + (index + 1) + ']'; + return this.getTodoListXpath() + '/li[' + (index + 1) + ']'; }; // ----------------- try / get methods @@ -19,63 +31,64 @@ module.exports = function Page(browser) { // elements which *might* be present in the DOM, hence the try/get name. this.tryGetMainSectionElement = function () { - return browser.findElements(webdriver.By.xpath('//section[@id="main"]')); + return this.tryFindByXpath('//section[@id="main"]'); }; this.tryGetFooterElement = function () { - return browser.findElements(webdriver.By.xpath('//footer[@id="footer"]')); + return this.tryFindByXpath('//footer[@id="footer"]'); }; this.tryGetClearCompleteButton = function () { - return browser.findElements(webdriver.By.xpath('//button[@id="clear-completed"]')); + return this.tryFindByXpath('//button[@id="clear-completed"]'); }; this.tryGetToggleForItemAtIndex = function (index) { var xpath = this.xPathForItemAtIndex(index) + '//input[contains(@class,"toggle")]'; - return browser.findElements(webdriver.By.xpath(xpath)); + return this.tryFindByXpath(xpath); }; this.tryGetItemLabelAtIndex = function (index) { - return browser.findElements(webdriver.By.xpath(this.xPathForItemAtIndex(index) + '//label')); + return this.tryFindByXpath(this.xPathForItemAtIndex(index) + '//label'); }; // ----------------- DOM element access methods this.getEditInputForItemAtIndex = function (index) { var xpath = this.xPathForItemAtIndex(index) + '//input[contains(@class,"edit")]'; - return browser.findElement(webdriver.By.xpath(xpath)); + return this.findByXpath(xpath); }; this.getItemInputField = function () { - return browser.findElement(webdriver.By.xpath('//input[@id="new-todo"]')); + return this.findByXpath('//input[@id="new-todo"]'); }; this.getMarkAllCompletedCheckBox = function () { - return browser.findElement(webdriver.By.xpath('//input[@id="toggle-all"]')); + return this.findByXpath('//input[@id="toggle-all"]'); }; this.getItemElements = function () { - return browser.findElements(webdriver.By.xpath('//ul[@id="todo-list"]/li')); + return this.tryFindByXpath(this.getTodoListXpath() + '/li'); }; this.getNonCompletedItemElements = function () { - return browser.findElements(webdriver.By.xpath('//ul[@id="todo-list"]/li[not(contains(@class,"completed"))]')); + return this.tryFindByXpath(this.getTodoListXpath() + '/li[not(contains(@class,"completed"))]'); }; this.getItemsCountElement = function () { - return browser.findElement(webdriver.By.id('todo-count')); + return this.findByXpath('//span[@id="todo-count"]'); }; this.getItemLabelAtIndex = function (index) { - return browser.findElement(webdriver.By.xpath(this.xPathForItemAtIndex(index) + '//label')); + return this.findByXpath(this.xPathForItemAtIndex(index) + '//label'); }; this.getFilterElements = function () { - return browser.findElements(webdriver.By.xpath('//ul[@id="filters"]//a')); + return this.tryFindByXpath('//ul[@id="filters"]//a'); }; this.getItemLabels = function () { - return browser.findElements(webdriver.By.xpath('//ul[@id="todo-list"]/li//label')); + var xpath = this.getTodoListXpath() + '/li//label'; + return this.tryFindByXpath(xpath); }; // ----------------- page actions diff --git a/browser-tests/pageLaxMode.js b/browser-tests/pageLaxMode.js index 65fb86fabd..52b1c3e44d 100644 --- a/browser-tests/pageLaxMode.js +++ b/browser-tests/pageLaxMode.js @@ -6,6 +6,37 @@ var Page = require('./page'); module.exports = function PageLaxMode(browser) { Page.apply(this, [browser]); + + this.getTodoListXpath = function() { + return '(//section/ul | //section/div/ul | //ul[@id="todo-list"])'; + } + + this.getMarkAllCompletedCheckBox = function () { + var xpath = '(//section/input[@type="checkbox"] | //section/*/input[@type="checkbox"] | //input[@id="toggle-all"])'; + return browser.findElement(webdriver.By.xpath(xpath)); + }; + + this.tryGetClearCompleteButton = function () { + var xpath = '(//footer/button | //footer/*/button | //button[@id="clear-completed"])'; + return browser.findElements(webdriver.By.xpath(xpath)); + }; + + this.getItemsCountElement = function () { + var xpath = '(//footer/span | //footer/*/span)'; + return browser.findElement(webdriver.By.xpath(xpath)); + }; + + this.getFilterElements = function () { + return browser.findElements(webdriver.By.xpath('//footer//ul//a')); + }; + + + this.getItemInputField = function () { + // allow a more generic method for locating the text getItemInputField + var xpath = '(//header/input | //header/*/input | //input[@id="new-todo"])'; + return browser.findElement(webdriver.By.xpath(xpath)); + }; + this.tryGetToggleForItemAtIndex = function (index) { // the specification dictates that the checkbox should have the 'toggle' CSS class. Some implementations deviate from // this, hence in lax mode we simply look for any checkboxes within the specified 'li'. @@ -16,7 +47,6 @@ module.exports = function PageLaxMode(browser) { this.getEditInputForItemAtIndex = function (index) { // the specification dictates that the input element that allows the user to edit a todo item should have a CSS // class of 'edit'. In lax mode, we also look for an input of type 'text'. - var xpath = '(' + this.xPathForItemAtIndex(index) + '//input[@type="text"]' + '|' + this.xPathForItemAtIndex(index) + '//input[contains(@class,"edit")]' + ')'; return browser.findElement(webdriver.By.xpath(xpath)); diff --git a/browser-tests/test.js b/browser-tests/test.js index b06d9e6a7a..1f4ecc385c 100644 --- a/browser-tests/test.js +++ b/browser-tests/test.js @@ -283,7 +283,7 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod }); }); - test.describe('Persistence', function () { + /*test.describe('Persistence', function () { test.it('should persist its data', function () { // set up state page.enterItem(TODO_ITEM_ONE); @@ -306,7 +306,7 @@ module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMod // repeat the state test stateTest(); }); - }); + });*/ test.describe('Routing', function () { test.it('should allow me to display active items', function () { diff --git a/browser-tests/testOperations.js b/browser-tests/testOperations.js index 43b814c06f..92b17b8e58 100644 --- a/browser-tests/testOperations.js +++ b/browser-tests/testOperations.js @@ -107,7 +107,7 @@ function TestOperations(page) { this.assertItems = function (textArray) { page.getItemLabels().then(function (labels) { assert.equal(textArray.length, labels.length, - textArray.length, + ' items expected in the todo list, ' + labels.length + ' items observed'); + textArray.length + ' items expected in the todo list, ' + labels.length + ' items observed'); // create an array of promises which check the presence of the // label text within the 'textArray' var tests = [];