Refactor smoke test, add a second one

This commit is contained in:
Scott Erickson 2016-09-20 15:02:15 -07:00
parent 12baae7acd
commit 6f6c3406ac
9 changed files with 241 additions and 103 deletions

View file

@ -1,7 +1,7 @@
{ {
"src_folders": ["spec/smoke"], "src_folders": ["spec/smoke/tests"],
"output_folder": "spec/smoke/reports", "output_folder": "spec/smoke/reports",
"custom_commands_path": "", "custom_commands_path": "spec/smoke/commands",
"custom_assertions_path": "", "custom_assertions_path": "",
"page_objects_path": "", "page_objects_path": "",
"globals_path": "", "globals_path": "",

View file

@ -0,0 +1,29 @@
constants = require('../constants');
exports.command = function(callback) {
return this
.timeoutsAsyncScript(constants.ASYNC_TIMEOUT * 4) // Make it extra long for production
.executeAsync(function(done) {
waitForApplication = function () {
if (window.application) { waitForCurrentView() }
else { setTimeout(waitForApplication, 1) }
}
waitForCurrentView = function () {
if (window.currentView && window.currentView.supermodel) { waitForCurrentViewToLoad() }
else { setTimeout(waitForCurrentView, 1) }
}
waitForCurrentViewToLoad = function () {
if (window.currentView.supermodel.finished()) { done() }
else { setTimeout(waitForCurrentViewToLoad) }
}
waitForApplication();
}, [], function(result) {
if(result.error)
console.log('waitForApplicationLoaded error:', result.error, result)
})
.pause(constants.PAUSE_TIME)
};

View file

@ -0,0 +1,8 @@
constants = require('../constants');
exports.command = function(selector) {
return this
.waitForElementVisible(selector, constants.ASYNC_TIMEOUT)
.pause(constants.PAUSE_TIME)
.click(selector);
};

View file

@ -0,0 +1,21 @@
constants = require('../constants');
exports.command = function() {
return this
.timeoutsAsyncScript(constants.ASYNC_TIMEOUT)
.executeAsync(function(done) {
try {
window.currentModal.supermodel.finishLoading()
.then(function() { done(); })
.catch(function(e) { console.error('Promise error', e); done(e); });
}
catch (e) {
console.error('Caught error:', e);
done(e);
}
}, [], function(result) {
if(result.error)
console.log('waitForModalLoaded error:', result.error)
})
.pause(constants.PAUSE_TIME)
};

View file

@ -0,0 +1,21 @@
constants = require('../constants');
exports.command = function() {
return this
.timeoutsAsyncScript(constants.ASYNC_TIMEOUT)
.executeAsync(function(done) {
try {
window.currentView.supermodel.finishLoading()
.then(function() { done(); })
.catch(function(e) { console.error('Promise error', e); done(e); });
}
catch (e) {
console.error('Caught error:', e);
done(e);
}
}, [], function(result) {
if(result.error)
console.log('waitForViewLoaded error:', result.error)
})
.pause(constants.PAUSE_TIME);
};

23
spec/smoke/constants.js Normal file
View file

@ -0,0 +1,23 @@
switch (process.env.COCO_SMOKE_DOMAIN) {
case "local":
module.exports.DOMAIN = 'http://localhost:3000';
break;
case "next":
module.exports.DOMAIN = 'http://next.codecombat.com';
break;
case "staging":
module.exports.DOMAIN = 'http://staging.codecombat.com';
break;
case "prod":
module.exports.DOMAIN = 'https://codecombat.com';
break;
default:
module.exports.DOMAIN = 'http://localhost:3000';
}
// General time to wait for elements to appear
module.exports.ASYNC_TIMEOUT = 8000;
// Used after an element appears, before an action occurs, to give the UI time to catch up,
// and to make the smoke test more 'watchable'.
module.exports.PAUSE_TIME = 300;

View file

@ -1,101 +0,0 @@
WAIT_TIMEOUT = 8000;
// TODO: Refactor into shared file
switch (process.env.COCO_SMOKE_DOMAIN) {
case "local":
DOMAIN = 'http://localhost:3000';
break;
case "next":
DOMAIN = 'http://next.codecombat.com';
break;
case "staging":
DOMAIN = 'http://staging.codecombat.com';
break;
case "prod":
DOMAIN = 'https://codecombat.com';
break;
default:
DOMAIN = 'http://localhost:3000';
}
var timestamp = new Date().getTime(),
email = `email${timestamp}@${timestamp}.com`,
name = timestamp.toString(),
password = timestamp.toString();
module.exports = {
'Sign up': function (browser) {
browser
// Go to home page
.url(DOMAIN)
.resizeWindow(1250, 900)
// Open login modal
.executeAsync(function(done) { window.currentView.supermodel.finishLoading.then(done); })
.click('#create-account-link')
// Sign up
.waitForElementVisible('.individual-path-button', WAIT_TIMEOUT)
.click('.individual-path-button')
.waitForElementVisible('#birthday-month-input', WAIT_TIMEOUT)
.setValue('#birthday-month-input', 'January')
.setValue('#birthday-day-input', '1')
.setValue('#birthday-year-input', '1999')
.click('.next-button')
.waitForElementVisible('input[name="email"]', WAIT_TIMEOUT)
.setValue('input[name="email"]', email)
.setValue('input[name="name"]', name)
.setValue('input[name="password"]', password)
.click('#subscribe-input')
.pause(100) // Sometimes create account button does not get clicked
.click('#create-account-btn')
.waitForElementVisible('#start-btn', WAIT_TIMEOUT)
.click('#start-btn')
// Confirm we went to campaign view, navigate back to home
.waitForElementVisible('#logout-button', WAIT_TIMEOUT * 3) // takes particularly long
.assert.urlContains('/play')
},
'Logout': function (browser) {
browser
.url(DOMAIN)
.executeAsync(function (done) {
window.currentView.supermodel.finishLoading.then(done);
})
.click('.dropdown-toggle')
.waitForElementVisible('.dropdown #logout-button', WAIT_TIMEOUT)
.click('.dropdown #logout-button')
},
'Log back in': function (browser) {
browser
// Log back in
.waitForElementVisible('#login-link', WAIT_TIMEOUT)
.click('#login-link')
.waitForElementVisible('#login-btn', WAIT_TIMEOUT)
.setValue('input#username-or-email-input', email)
.setValue('input#password-input', password)
.click('#login-btn')
.pause(100)
.waitForElementVisible('#main-nav', WAIT_TIMEOUT)
},
'Delete account': function (browser) {
browser
// Delete account
.url(`${DOMAIN}/account/settings`)
.pause(100)
.executeAsync(function(done) { window.currentView.supermodel.finishLoading.then(done); })
.waitForElementVisible('#delete-account-email-or-username', WAIT_TIMEOUT)
.setValue('#delete-account-email-or-username', email)
.setValue('#delete-account-password', password)
.click('#delete-account-btn')
.waitForElementVisible('#confirm-button', WAIT_TIMEOUT)
.click('#confirm-button')
.end();
}
};

View file

@ -0,0 +1,92 @@
constants = require('../constants');
var timestamp = new Date().getTime(),
email = `email${timestamp}@${timestamp}.com`,
name = timestamp.toString(),
password = timestamp.toString();
module.exports = {
'Sign up': function (browser) {
browser
// Go to home page
.url(constants.DOMAIN)
.resizeWindow(1250, 900)
// Open login modal
.waitForApplicationLoaded()
.click('#create-account-link')
// Sign up
.waitForModalLoaded()
.click('.individual-path-button')
.waitForElementVisibleAndClick('#birthday-month-input')
.setValue('#birthday-month-input', 'January')
.setValue('#birthday-day-input', '1')
.setValue('#birthday-year-input', '1999')
.pause(constants.PAUSE_TIME)
.click('.next-button')
.waitForElementVisible('input[name="email"]', constants.ASYNC_TIMEOUT)
.executeAsync(function(done) {
// If G+ or FB load in the middle of execution, they re-render the modal. This code waits for both
// to load before continuing. TODO: Refactor code so this is unnecessary.
check = function() {
if(currentModal.signupState.get('facebookEnabled') && currentModal.signupState.get('gplusEnabled')) {
done()
}
}
currentModal.signupState.on('change', check);
check();
}, [], function(res) { if(res.error) { console.error('G+/FB wait error:', res.error) } })
.pause(constants.PAUSE_TIME)
.setValue('input[name="email"]', email)
.setValue('input[name="name"]', name)
.setValue('input[name="password"]', password)
.click('#subscribe-input')
.pause(constants.PAUSE_TIME*2)
.click('#create-account-btn')
.waitForElementVisibleAndClick('#start-btn')
// Confirm we went to campaign view, navigate back to home
.waitForElementVisible('#logout-button', constants.ASYNC_TIMEOUT * 3) // takes particularly long
.assert.urlContains('/play')
},
'Logout': function (browser) {
browser
.url(constants.DOMAIN)
.waitForViewLoaded()
.pause(constants.PAUSE_TIME)
.click('.dropdown-toggle')
.waitForElementVisibleAndClick('.dropdown #logout-button')
},
'Log back in': function (browser) {
browser
.waitForElementVisibleAndClick('#login-link')
.waitForElementVisible('#login-btn', constants.ASYNC_TIMEOUT)
.setValue('input#username-or-email-input', email)
.setValue('input#password-input', password)
.pause(constants.PAUSE_TIME)
.click('#login-btn')
.waitForElementVisible('#main-nav', constants.ASYNC_TIMEOUT)
.pause(constants.PAUSE_TIME)
},
'Delete account': function (browser) {
browser
.url(`${constants.DOMAIN}/account/settings`)
.pause(constants.PAUSE_TIME)
.waitForViewLoaded()
.waitForElementVisible('#delete-account-email-or-username', constants.ASYNC_TIMEOUT)
.setValue('#delete-account-email-or-username', email)
.setValue('#delete-account-password', password)
.pause(constants.PAUSE_TIME)
.click('#delete-account-btn')
.waitForElementVisibleAndClick('#confirm-button')
.pause(constants.PAUSE_TIME*2)
.end();
}
};

View file

@ -0,0 +1,45 @@
constants = require('../constants');
module.exports = {
'Go to dungeon campaign': function (browser) {
browser
.url(constants.DOMAIN + '/play/dungeon')
.resizeWindow(1250, 900)
.waitForApplicationLoaded()
},
'Go to level view for Dungeons of Kithgard': function (browser) {
browser
.click('a[data-level-slug="dungeons-of-kithgard"]')
.pause(constants.PAUSE_TIME)
.click('.start-level')
.pause(constants.PAUSE_TIME)
.waitForModalLoaded()
.waitForElementVisibleAndClick('#confirm-button')
.waitForElementVisibleAndClick('.btn.equip-item')
.click('#play-level-button')
.pause(constants.PAUSE_TIME)
},
'Play Dungeons of Kithgard': function (browser) {
browser
.waitForElementVisibleAndClick('button.start-level-button')
.keys([browser.Keys.ESCAPE])
.pause(constants.PAUSE_TIME)
.keys('hero.moveDown()\nhero.moveRight()\n')
.pause(constants.PAUSE_TIME)
.click('.cast-button')
.pause(constants.PAUSE_TIME)
.waitForElementVisibleAndClick('.done-button')
},
'Go through victory modal, check that Gems in the Deep is unlocked': function (browser) {
browser
.waitForModalLoaded()
.click('#continue-button')
.pause(constants.PAUSE_TIME)
.waitForElementVisible('a[data-level-slug="gems-in-the-deep"]', constants.ASYNC_TIMEOUT)
.pause(constants.PAUSE_TIME)
.end()
}
}