test(functional): remove old functional intern tests and files

This reverts commit 375aeb0570c8b7ecf424079153637d9c36824d32.
This commit is contained in:
Ankita Shrivastava 2023-10-10 14:40:23 -04:00
Родитель 3733a298f5
Коммит 5a5e8e7b49
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 53FC2CE37F83778D
83 изменённых файлов: 1 добавлений и 16656 удалений

Просмотреть файл

@ -25,13 +25,6 @@
"start-production": "NODE_ENV=production grunt build && yarn build-css && CONFIG_FILES=server/config/local.json,server/config/production.json,server/config/secrets.json grunt serverproc:dist",
"start-remote": "scripts/run_remote_dev.sh",
"test": "node tests/intern.js --unit=true",
"test-functional": "node tests/intern.js",
"test-functional-oauth": "node tests/intern.js --grep='oauth'",
"test-functional-settings": "node tests/intern.js --suites=settings",
"test-latest": "SKIP_MOCHA=true node tests/intern.js --fxaAuthRoot=https://latest.dev.lcip.org/auth/v1 --fxaContentRoot=https://latest.dev.lcip.org/ --fxaEmailRoot=http://restmail.net --fxaOAuthApp=https://123done-latest.dev.lcip.org/ --fxaUntrustedOauthApp=https://321done-latest.dev.lcip.org/ --fxaProduction=true --fxaToken=https://token.dev.lcip.org/1.0/sync/1.5",
"test-pairing": "node tests/intern.js --suites=pairing",
"test-pairing-circle": "node tests/intern.js --suites=pairing --fxaAuthRoot=https://fxaci.dev.lcip.org/auth --fxaEmailRoot=http://restmail.net --fxaOAuthApp=https://123done-fxaci.dev.lcip.org/ --fxaProduction=true --bailAfterFirstFailure=true",
"test-server": "node tests/intern.js --suites=server",
"format": "prettier --write --config ../../_dev/.prettierrc '**'"
},
"repository": {

Просмотреть файл

@ -1,58 +0,0 @@
#!/bin/bash -ex
DIR=$(dirname "$0")
cd "$DIR/.."
echo -e "\n###################################"
echo "# testing fxa-content-server"
echo -e "###################################\n"
env | sort
function test_suite() {
local suite=$1
local numGroups=$2
local i=$3
local fxaAccountsApiDomain="${ACCOUNTS_API_DOMAIN:-api-accounts.stage.mozaws.net}"
local fxaAccountsDomain="${ACCOUNTS_DOMAIN:-accounts.stage.mozaws.net}"
local relierDomain="${RELIER_DOMAIN:-stage-123done.herokuapp.com}"
local untrustedRelierDomain="${UNTRUSTED_RELIER_DOMAIN:-stage-123done-untrusted.herokuapp.com}"
node tests/intern.js \
--suites="${suite}" \
--fxaAuthRoot=https://${fxaAccountsApiDomain}/v1 \
--fxaContentRoot=https://${fxaAccountsDomain}/ \
--fxaOAuthApp=https://${relierDomain}/ \
--fxaUntrustedOauthApp=https://${untrustedRelierDomain}/ \
--fxaEmailRoot=http://restmail.net \
--fxaProduction=true \
--output="../../artifacts/tests/${suite}-${numGroups}-${i}-results.xml" \
--testProductId="prod_FiJ42WCzZNRSbS" \
--testPlanId="plan_HJyNT4gbuyyZ0G" \
--groups=${numGroups} \
--groupIndex=${i} \
|| \
node tests/intern.js \
--suites="${suite}" \
--fxaAuthRoot=https://${fxaAccountsApiDomain}/v1 \
--fxaContentRoot=https://${fxaAccountsDomain}/ \
--fxaOAuthApp=https://${relierDomain}/ \
--fxaUntrustedOauthApp=https://${untrustedRelierDomain}/ \
--fxaEmailRoot=http://restmail.net \
--fxaProduction=true \
--output="../../artifacts/tests/${suite}-${numGroups}-${i}-results.xml" \
--grep="$(<rerun.txt)" \
--testProductId="prod_FiJ42WCzZNRSbS" \
--testPlanId="plan_HJyNT4gbuyyZ0G" \
--groups=${numGroups} \
--groupIndex=${i}
}
cd ../../
mkdir -p artifacts/tests
cd packages/fxa-content-server
test_suite functional_smoke $CIRCLE_NODE_TOTAL $CIRCLE_NODE_INDEX && test_suite functional_regression $CIRCLE_NODE_TOTAL $CIRCLE_NODE_INDEX
# TODO: Re-enable once configuration in stage is updated
# test_suite pairing

Просмотреть файл

@ -1,25 +0,0 @@
#!/bin/bash -ex
DIR=$(dirname "$0")
function test_suite() {
local suite=$1
local numGroups=$2
for i in $(seq "$numGroups")
do
node tests/intern.js --suites="${suite}" --output="../../artifacts/tests/${suite}-${numGroups}-${i}-results.xml" --groupsCount="${numGroups}" --groupNum="${i}" || \
node tests/intern.js --suites="${suite}" --output="../../artifacts/tests/${suite}-${numGroups}-${i}-results.xml" --groupsCount="${numGroups}" --groupNum="${i}" --grep="$(<rerun.txt)"
done
}
cd "$DIR/.."
test_suite circle 3
# The last node currently has the least work to do in the above tests
if [[ "${CIRCLE_NODE_INDEX}" == "2" ]]; then
node tests/intern.js --suites='server' --output='../../artifacts/tests/server-results.xml'
#Removing the flaky pairing suite, to be addressed in https://mozilla-hub.atlassian.net/browse/FXA-6558
#node tests/intern.js --suites='pairing' --output='../../artifacts/tests/pairing-results.xml'
fi

Просмотреть файл

@ -1,87 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const testsSettings = require('./functional_settings');
module.exports = testsSettings.concat([
// new and flaky tests above here',
// 'tests/functional/email_opt_in.js',
// 'tests/functional/fx_desktop_handshake.js',
// 'tests/functional/oauth_sign_up.js',
// 'tests/functional/pages.js',
// 'tests/functional/post_verify/force_password_change.js',
// 'tests/functional/post_verify/account_recovery.js',
// 'tests/functional/post_verify/secondary_email.js',
// 'tests/functional/sign_in.js',
// 'tests/functional/sign_in_blocked.js',
// 'tests/functional/sync_v3_sign_up.js',
// 'tests/functional/sync_v3_settings.js',
// Disabled because of https://github.com/mozilla/fxa/issues/9863
// 'tests/functional/verification_reminders.js',
// These tests no longer adds value and have been removed as
// part of the analysis in
// https://docs.google.com/spreadsheets/d/11Wq-Y-ipeNFXqLHbr3GJCh_f_qEAG-CUuqBt5Dcnh5k/edit#gid=0
// 'tests/functional/bounced_email.js',
// 'tests/functional/sync_v1.js',
// 'tests/functional/pp.js',
// 'tests/functional/sync_v2.js',
// 'tests/functional/fx_firstrun_v2.js',
// 'tests/functional/tos.js',
// 'tests/functional/confirm.js',
//'tests/functional/fx_ios_v1_sign_in.js',
//'tests/functional/fx_ios_v1_sign_up.js',
//'tests/functional/oauth_query_param_validation.js',
//'tests/functional/refreshes_metrics.js',
//'tests/functional/fx_browser_relier.js',
//'tests/functional/500.js',
//'tests/functional/email_domain_mx_validation.js',
//'tests/functional/post_verify/newsletters.js',
//''tests/functional/robots_txt.js',
//'tests/functional/push.js',
//''tests/functional/back_button_after_start.js',
// Disabled because this test migrated to Playwright
// See `/functional-test`
// 'tests/functional/oauth_handshake.js',
// 'tests/functional/oauth_force_auth.js',
// 'tests/functional/sync_v3_force_auth.js',
// 'tests/functional/oauth_sign_in.js',
//'tests/functional/subscriptions.js',
//'tests/functional/support.js',
// 'tests/functional/password_visibility.js',
//'tests/functional/password_strength.js',
//'tests/functional/avatar.js',
//'tests/functional/settings/change_password.js',
//'tests/functional/settings/connected_services_oauth_clients.js',
//'tests/functional/settings/external_links.js',
//'tests/functional/settings/recovery_key.js',
//'tests/functional/settings/secondary_email.js',
//'tests/functional/settings/two_step_auth.js',
//'tests/functional/sign_up_with_code.js',
//'tests/functional/sync_v3_email_first.js',
// 'tests/functional/reset_password.js',
//'tests/functional/oauth_reset_password.js',
// 'tests/functional/legal.js',
//'tests/functional/sign_in_cached.js',
// 'tests/functional/cookies_disabled.js',
//'tests/functional/sign_up.js',
//'tests/functional/oauth_settings_clients.js',
//'tests/functional/oauth_require_totp.js',
//'tests/functional/force_auth.js',
//'tests/functional/sync_v3_sign_in.js',
//'tests/functional/sync_v3_reset_password.js',
//'tests/functional/oauth_sync_sign_in.js',
//'tests/functional/oauth_permissions.js',
//'tests/functional/oauth_prompt_none.js',
]);
// Mocha tests are only exposed during local dev, not on prod-like
// instances such as latest, stable, stage, and prod. To avoid
// Teamcity failing trying to run mocha tests, expose an environment
// variable it can use to skip the mocha tests.
if (!process.env.SKIP_MOCHA) {
module.exports.unshift('tests/functional/mocha.js');
}

Просмотреть файл

@ -1,26 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const selectors = require('./lib/selectors');
const { click, openPage, clearBrowserState } = require('./lib/helpers');
registerSuite('404', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ forceAll: true }));
},
tests: {
'visit an invalid page': function () {
const url = `${intern._config.fxaContentRoot}/four-oh-four`;
return this.remote
.then(openPage(url, selectors['404'].HEADER))
.then(click(selectors['404'].LINK_HOME, selectors.ENTER_EMAIL.HEADER));
},
},
});

Просмотреть файл

@ -1,32 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { registerSuite } = intern.getInterface('object');
const selectors = require('./lib/selectors');
const { clearBrowserState, click, openPage } = require('./lib/helpers');
const url = intern._config.fxaContentRoot + 'boom';
registerSuite('500', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ forceAll: true }));
},
tests: {
'visit an invalid page': function () {
const expected = intern._config.fxaProduction
? selectors['404'].HEADER
: selectors['500'].HEADER;
const button = intern._config.fxaProduction
? selectors['404'].LINK_HOME
: selectors['500'].LINK_HOME;
return this.remote
.then(openPage(url, expected))
.then(click(button, selectors.ENTER_EMAIL.HEADER));
},
},
});

Просмотреть файл

@ -1,189 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const path = require('path');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const PASSWORD = 'passwordzxcv';
const SETTINGS_URL = config.fxaContentRoot + 'settings';
const ENTER_EMAIL_URL = config.fxaContentRoot + '?action=email';
const UPLOAD_IMAGE_PATH = path.join(
process.cwd(),
'app',
'apple-touch-icon-152x152.png'
);
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
getWebChannelMessageData,
openPage,
storeWebChannelMessageData,
testElementExists,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('settings/avatar', {
// In order to test creating an avatar from a webcam on a headless test
// machine, we set the 'media.navigator.streams.fake' browser pref, which
// instructs the browser to return a fake stream from getUserMedia requests.
// It turns out browser profile changes aren't reset between test runs, so
// we just need to flip the pref once, and reset it when we're done. There's
// probably a clever way to do this in a config file, but here we simply use
// browser automation to load about:config and change the values directly.
before: function () {
return this.remote
.then(openPage('about:config'))
.then(click('#warningButton'))
.then(type('#about-config-search', 'media.navigator.streams.fake'))
.then(click('.button-toggle'));
},
after: function () {
return this.remote
.then(openPage('about:config'))
.then(click('#warningButton'))
.then(type('#about-config-search', 'media.navigator.streams.fake'))
.then(click('.button-reset'));
},
beforeEach: function () {
email = createEmail();
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState({ force: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
tests: {
'attempt to use webcam for avatar': function () {
return (
this.remote
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
// go to change avatar
.then(click(selectors.SETTINGS_AVATAR.MENU_BUTTON))
.then(storeWebChannelMessageData('profile:change'))
// click button, look for the loading spinner
.then(click(selectors.SETTINGS_AVATAR.BUTTON_CAMERA))
.then(click(selectors.SETTINGS_AVATAR.BUTTON_CAPTURING))
.then(click(selectors.SETTINGS_AVATAR.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
//success is seeing the image loaded
.then(testElementExists(selectors.SETTINGS_AVATAR.NON_DEFAULT_IMAGE))
// Replacement for testIsBrowserNotified
.then(getWebChannelMessageData('profile:change'))
.then((msg) => {
assert.equal(msg.command, 'profile:change');
})
);
},
'attempt to use webcam for avatar, then cancel': function () {
return (
this.remote
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
// go to change avatar
.then(click(selectors.SETTINGS_AVATAR.MENU_BUTTON))
.then(click(selectors.SETTINGS_AVATAR.BUTTON_CAMERA))
// look for the button shown when the webcam capture has begun
.then(testElementExists(selectors.SETTINGS_AVATAR.BUTTON_CAPTURING))
.then(click(selectors.SETTINGS_AVATAR.BACK))
// success is returning to the settings page
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'upload and then remove profile image': function () {
return (
this.remote
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
.then(click(selectors.SETTINGS_AVATAR.MENU_BUTTON))
.then(storeWebChannelMessageData('profile:change'))
// Selenium's way of interacting with a file picker
.findByCssSelector(selectors.SETTINGS_AVATAR.UPLOAD_FILENAME_INPUT)
.type(UPLOAD_IMAGE_PATH)
.end()
.then(testElementExists(selectors.SETTINGS_AVATAR.BUTTON_ROTATE))
.then(click(selectors.SETTINGS_AVATAR.BUTTON_ZOOM_OUT))
.then(click(selectors.SETTINGS_AVATAR.BUTTON_ZOOM_IN))
.then(click(selectors.SETTINGS_AVATAR.BUTTON_ROTATE))
.then(
click(
selectors.SETTINGS_AVATAR.SUBMIT,
selectors.SETTINGS_AVATAR.NON_DEFAULT_IMAGE
)
)
//success is seeing the image loaded and navigated to settings
.then(testElementExists(selectors.SETTINGS_AVATAR.NON_DEFAULT_IMAGE))
.then(visibleByQSA(selectors.SETTINGS.HEADER))
// Replacement for testIsBrowserNotified
.then(getWebChannelMessageData('profile:change'))
.then((msg) => {
assert.equal(msg.command, 'profile:change');
})
// Remove the uploaded image
.then(click(selectors.SETTINGS_AVATAR.MENU_BUTTON))
.then(click(selectors.SETTINGS_AVATAR.REMOVE_BUTTON))
// Success is navigating to settings and seeing no image
.then(visibleByQSA(selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.SETTINGS_AVATAR.NON_DEFAULT_IMAGE))
);
},
'cancel uploading a profile image': function () {
return (
this.remote
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
.then(click(selectors.SETTINGS_AVATAR.MENU_BUTTON))
// Selenium's way of interacting with a file picker
.findByCssSelector(selectors.SETTINGS_AVATAR.UPLOAD_FILENAME_INPUT)
.type(UPLOAD_IMAGE_PATH)
.end()
.then(testElementExists(selectors.SETTINGS_AVATAR.BUTTON_ROTATE))
.then(click(selectors.SETTINGS_AVATAR.BACK))
// success is returning to the settings page
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'redirects from /settings/avatar/change to /settings/avatar': function () {
return (
this.remote
.then(openPage(SETTINGS_URL + '/avatar/change'))
//success is being redirected to /avatar and seeing the page load
.then(testElementExists(selectors.SETTINGS_AVATAR.BUTTON_CAMERA))
);
},
},
});

Просмотреть файл

@ -1,38 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const { assert } = intern.getPlugin('chai');
const { openPage, clearBrowserState } = require('./lib/helpers');
const selectors = require('./lib/selectors');
var FROM_URL = 'http://example.com/';
var ENTER_EMAIL_URL = intern._config.fxaContentRoot;
registerSuite('back button after navigating to the root', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ forceAll: true }));
},
tests: {
'start at github, visit Fxa root, click `back` - should go back to example': function () {
return (
this.remote
.get(FROM_URL)
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
// click back.
.goBack()
.getCurrentUrl()
.then(function (resultUrl) {
assert.equal(resultUrl, FROM_URL);
})
.end()
);
},
},
});

Просмотреть файл

@ -1,173 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
let bouncedEmail;
let deliveredEmail;
const PASSWORD = 'password12345678';
const ENTER_EMAIL_URL = `${
intern._config.fxaContentRoot
}?context=fx_desktop_v3&service=sync&forceUA=${encodeURIComponent(
uaStrings.desktop_firefox_58
)}`; //eslint-disable-line max-len
const {
clearBrowserState,
click,
closeCurrentWindow,
createEmail,
createUser,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
getFxaClient,
openPage,
pollUntil,
respondToWebChannelMessage,
switchToWindow,
testElementExists,
testElementValueEquals,
testIsBrowserNotified,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('signup with an email that bounces', {
beforeEach: function () {
bouncedEmail = createEmail();
deliveredEmail = createEmail();
return (
this.remote
.then(clearBrowserState())
// ensure a fresh signup page is loaded. If this suite is
// run after a Sync suite, these tests try to use a Sync broker
// which results in a channel timeout.
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
);
},
tests: {
'sign up, bounce email at /choose_what_to_sync, allow user to restart flow but force a different email': function () {
const client = getFxaClient();
return (
this.remote
.then(fillOutEmailFirstSignUp(bouncedEmail, PASSWORD))
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(() => client.accountDestroy(bouncedEmail, PASSWORD))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// The first can_link_account handler is removed, hook up another.
.then(
respondToWebChannelMessage('fxaccounts:can_link_account', {
ok: true,
})
)
// expect an error message to already be present on redirect
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP_BOUNCED_EMAIL))
.then(type(selectors.ENTER_EMAIL.EMAIL, bouncedEmail))
// user must change the email address
.then(click(selectors.ENTER_EMAIL.SUBMIT))
// error message should still be around
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP_BOUNCED_EMAIL))
.then(type(selectors.ENTER_EMAIL.EMAIL, deliveredEmail))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
// password is remembered
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.CHOOSE_WHAT_TO_SYNC.HEADER
)
)
.then(
click(
selectors.CHOOSE_WHAT_TO_SYNC.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
);
},
},
});
const setUpBouncedSignIn = thenify(function (email) {
const client = getFxaClient();
email = email || createEmail('sync{id}');
return this.parent
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(() => client.accountDestroy(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_BOUNCED.HEADER))
.then(testElementExists(selectors.SIGNIN_BOUNCED.CREATE_ACCOUNT))
.then(testElementExists(selectors.SIGNIN_BOUNCED.BACK))
.then(testElementExists(selectors.SIGNIN_BOUNCED.SUPPORT));
});
registerSuite('signin with an email that bounces', {
tests: {
'click create-account': function () {
return this.remote
.then(setUpBouncedSignIn())
.then(click(selectors.SIGNIN_BOUNCED.CREATE_ACCOUNT))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, ''));
},
'click back': function () {
const email = createEmail('sync{id}');
return this.remote
.then(setUpBouncedSignIn(email))
.then(click(selectors.SIGNIN_BOUNCED.BACK))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
.then(
testElementValueEquals(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD)
);
},
'click support': function () {
return this.remote
.then(setUpBouncedSignIn())
.then(click(selectors.SIGNIN_BOUNCED.SUPPORT))
.then(switchToWindow(1))
.then(
pollUntil(() =>
window.location.href.startsWith('https://support.mozilla.org/')
)
)
.then(closeCurrentWindow());
},
refresh: function () {
return this.remote
.then(setUpBouncedSignIn())
.refresh()
.then(
respondToWebChannelMessage('fxaccounts:fxa_status', {
capabilities: null,
signedInUser: null,
})
)
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER));
},
},
});

Просмотреть файл

@ -1,65 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const CONFIRM_URL = config.fxaContentRoot + 'confirm';
const ENTER_EMAIL_URL = config.fxaContentRoot;
const PASSWORD = 'password12345678';
const {
clearBrowserState,
click,
fillOutEmailFirstSignUp,
openPage,
testElementExists,
testElementTextInclude,
testSuccessWasShown,
} = FunctionalHelpers;
registerSuite('confirm', {
beforeEach: function () {
return this.remote.then(clearBrowserState());
},
tests: {
'visit confirmation screen without initiating sign up, user is redirected to /signup': function () {
return (
this.remote
// user is immediately redirected to / if they have no sessionToken.
.then(openPage(CONFIRM_URL, selectors.ENTER_EMAIL.HEADER))
);
},
'sign up, wait for confirmation screen, click resend': function () {
const email = 'test_signin' + Math.random() + '@restmail.net';
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(
testElementTextInclude(
selectors.CONFIRM_SIGNUP_CODE.EMAIL_FIELD,
email
)
)
.then(click(selectors.CONFIRM_SIGNUP_CODE.LINK_RESEND))
// the test below depends on the speed of the email resent XHR
// we have to wait until the resent request completes and the
// success notification is visible
.then(testSuccessWasShown(null, '.success'))
);
},
},
});

Просмотреть файл

@ -1,63 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const UA_STRINGS = require('./lib/ua-strings');
const selectors = require('./lib/selectors');
const config = intern._config;
const CONNECT_ANOTHER_DEVICE_URL = `${config.fxaContentRoot}connect_another_device`;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync&action=email`;
const {
clearBrowserState,
createEmail,
fillOutEmailFirstSignUp,
noSuchElement,
openPage,
testElementExists,
} = FunctionalHelpers;
let email;
const PASSWORD = 'password12345678';
registerSuite('connect_another_device', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'signup Fx Desktop, load /connect_another_device page': function () {
// should have both links to mobile apps
const forceUA = UA_STRINGS['desktop_firefox'];
return this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: { forceUA },
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(
openPage(
CONNECT_ANOTHER_DEVICE_URL,
selectors.CONNECT_ANOTHER_DEVICE.HEADER
)
)
.then(noSuchElement(selectors.CONNECT_ANOTHER_DEVICE.SIGNIN_BUTTON))
.then(
testElementExists(
selectors.CONNECT_ANOTHER_DEVICE.TEXT_INSTALL_FX_DESKTOP
)
)
.then(noSuchElement(selectors.CONNECT_ANOTHER_DEVICE.SUCCESS));
},
},
});

Просмотреть файл

@ -1,84 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const {
clearBrowserState,
click,
openPage,
testElementExists,
testErrorWasShown,
} = require('./lib/helpers');
const selectors = require('./lib/selectors');
// there is no way to disable cookies using wd. Add `disable_cookies`
// to the URL to synthesize cookies being disabled.
var config = intern._config;
var ENTER_EMAIL_COOKIES_DISABLED_URL =
config.fxaContentRoot + '?disable_local_storage=1';
var ENTER_EMAIL_COOKIES_ENABLED_URL = config.fxaContentRoot;
// Use fake, but real looking uid & code
const VERIFY_COOKIES_DISABLED_URL =
config.fxaContentRoot +
'verify_email?disable_local_storage=1&uid=240103bbecd645848103021e7d245bcb&code=fc46f44802b2a2ce979f39b2187aa1c0';
const COOKIES_DISABLED_URL = config.fxaContentRoot + 'cookies_disabled';
registerSuite('cookies_disabled', {
beforeEach() {
return this.remote.then(clearBrowserState());
},
tests: {
'visit signup page with localStorage disabled': function () {
return (
this.remote
.then(
openPage(
ENTER_EMAIL_COOKIES_DISABLED_URL,
selectors.COOKIES_DISABLED.HEADER
)
)
// try again, cookies are still disabled.
.then(click(selectors.COOKIES_DISABLED.RETRY))
// show an error message after second try
.then(testErrorWasShown(null, '.error'))
);
},
'synthesize enabling cookies by visiting the enter email page, then cookies_disabled, then clicking "try again"': function () {
// wd has no way of disabling/enabling cookies, so we have to
// manually seed history.
return (
this.remote
.then(
openPage(
ENTER_EMAIL_COOKIES_ENABLED_URL,
selectors.ENTER_EMAIL.HEADER
)
)
.then(
openPage(COOKIES_DISABLED_URL, selectors.COOKIES_DISABLED.HEADER)
)
// try again, cookies are enabled.
.then(click(selectors.COOKIES_DISABLED.RETRY))
// Should be redirected back to the signup page.
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
);
},
'visit verify page with localStorage disabled': function () {
return this.remote.then(
openPage(VERIFY_COOKIES_DISABLED_URL, selectors.COOKIES_DISABLED.HEADER)
);
},
},
});

Просмотреть файл

@ -1,91 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const EMAIL_FIRST_FORM_URL = intern._config.fxaContentRoot + '?action=email';
const INVALID_EMAIL = `nofxauser${Math.random()}@asdfafexample.xyz`;
const {
clearBrowserState,
click,
openPage,
testElementTextInclude,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('email domain mx record validation', {
beforeEach() {
return this.remote.then(clearBrowserState());
},
tests: {
'no validation on a popular domain': function () {
const email = `coolfxauser${Math.random()}@gmail.com`;
return this.remote
.then(openPage(EMAIL_FIRST_FORM_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
);
},
'show validation error on invalid domain': function () {
return this.remote
.then(openPage(EMAIL_FIRST_FORM_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, INVALID_EMAIL))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.ENTER_EMAIL.TOOLTIP)
)
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP))
.then(
testElementTextInclude(
selectors.ENTER_EMAIL.TOOLTIP,
'Mistyped email? asdfafexample.xyz does not offer email.'
)
);
},
'show tooltip on domain with an A record': function () {
const email = `coolfxauser${Math.random()}@mail.google.com`;
return this.remote
.then(openPage(EMAIL_FIRST_FORM_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.ENTER_EMAIL.SUGGEST_EMAIL_DOMAIN_CORRECTION
)
)
.then(
testElementTextInclude(
selectors.ENTER_EMAIL.SUGGEST_EMAIL_DOMAIN_CORRECTION,
'Mistyped email?'
)
)
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
);
},
'allow submission on domain with an MX record': function () {
const email = `coolfxauser${Math.random()}@mozilla.com`;
return this.remote
.then(openPage(EMAIL_FIRST_FORM_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
);
},
},
});

Просмотреть файл

@ -1,65 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const PAGE_URL = intern._config.fxaContentRoot + '?action=email';
let email;
const PASSWORD = '12345678';
const {
clearBrowserState,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
testAttribute,
testAttributeEquals,
} = FunctionalHelpers;
// okay, not remote so run these for real.
registerSuite('communication preferences', {
beforeEach: function () {
// The plus sign is to ensure the email address is URI-encoded when
// passed to basket. See a43061d3
email = createEmail('signup{id}+extra');
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState());
},
tests: {
'manage link': function () {
return (
this.remote
.then(openPage(PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// The manage link is not clicked because basket is not
// hooked up to latest, and the teamcity test runner
// gets redirected to a random allizom.org page.
// Check the link is formed as we expect it to be.
.then(
testAttribute(
selectors.SETTINGS_COMMUNICATION.BUTTON_MANAGE,
'href',
'include',
`email=${encodeURIComponent(email)}`
)
)
.then(
testAttributeEquals(
selectors.SETTINGS_COMMUNICATION.BUTTON_MANAGE,
'target',
'_blank'
)
)
);
},
},
});

Просмотреть файл

@ -1,113 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutForceAuth,
openForceAuth,
signOut,
testElementDisabled,
testElementExists,
testElementTextInclude,
testElementValueEquals,
type,
} = FunctionalHelpers;
const PASSWORD = 'passwordcxzv';
let email;
registerSuite('force_auth', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState());
},
tests: {
'with a registered email, registered uid': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(function (accountInfo) {
return openForceAuth({
query: {
email: email,
uid: accountInfo.uid,
},
}).call(this);
})
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'forgot password flow via force_auth': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openForceAuth({ query: { email: email } }))
.then(click(selectors.FORCE_AUTH.LINK_RESET_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
.then(testElementValueEquals(selectors.FORCE_AUTH.EMAIL, email))
.then(testElementDisabled(selectors.FORCE_AUTH.EMAIL))
.then(
testElementTextInclude(
selectors.FORCE_AUTH.EMAIL_NOT_EDITABLE,
email
)
)
// User thinks they have remembered their password, clicks the
// "sign in" link. Go back to /force_auth.
.then(click(selectors.RESET_PASSWORD.LINK_SIGNIN))
.then(testElementExists(selectors.FORCE_AUTH.HEADER))
// User goes back to reset password to submit.
.then(click(selectors.FORCE_AUTH.LINK_RESET_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
.then(click(selectors.RESET_PASSWORD.SUBMIT))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
// User has remembered their password, for real this time.
// Go back to /force_auth.
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_SIGNIN))
.then(testElementExists(selectors.FORCE_AUTH.HEADER))
.then(testElementValueEquals(selectors.FORCE_AUTH.EMAIL, email))
.then(testElementDisabled(selectors.FORCE_AUTH.EMAIL))
.then(
testElementTextInclude(
selectors.FORCE_AUTH.EMAIL_NOT_EDITABLE,
email
)
)
);
},
'form prefill information is cleared after sign in->sign out': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openForceAuth({ query: { email: email } }))
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(signOut())
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER)
)
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.PASSWORD, ''));
},
},
});

Просмотреть файл

@ -1,262 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { assert } = intern.getPlugin('chai');
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
const config = intern._config;
const URL_PARAMS = 'context=fx_desktop_v3&action=email';
const EMAIL_FIRST_URL = `${config.fxaContentRoot}?${URL_PARAMS}`;
const FIREFOX_CLIENT_ID = '5882386c6d801776';
const CAPABILITIES = {
multiService: true,
pairing: false,
engines: ['history'],
};
let email;
const PASSWORD = 'passwordvx2';
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
openPage,
testElementExists,
testIsBrowserNotified,
type,
} = FunctionalHelpers;
registerSuite('Firefox Desktop non-sync', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'signup with no service - sync': function () {
return (
this.remote
.then(
openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.SYNC_DESCRIPTION, {
query: {
forceUA: uaStrings['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
clientId: FIREFOX_CLIENT_ID,
capabilities: CAPABILITIES,
},
},
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.SUBMIT))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// verify the account
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
);
},
'signin with no service - do not sync': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.SYNC_DESCRIPTION, {
query: {
forceUA: uaStrings['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
clientId: FIREFOX_CLIENT_ID,
capabilities: CAPABILITIES,
},
},
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER)
)
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.WOULD_YOU_LIKE_SYNC.HEADER
)
)
.then(
click(
selectors.WOULD_YOU_LIKE_SYNC.DO_NOT_SYNC,
selectors.CONNECT_ANOTHER_DEVICE.HEADER
)
)
.then(testIsBrowserNotified('fxaccounts:login'));
},
'signin with no service - sync': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.SYNC_DESCRIPTION, {
query: {
forceUA: uaStrings['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
clientId: FIREFOX_CLIENT_ID,
capabilities: CAPABILITIES,
},
},
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER)
)
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.WOULD_YOU_LIKE_SYNC.HEADER
)
)
.then(
click(
selectors.WOULD_YOU_LIKE_SYNC.SUBMIT,
selectors.CONNECT_ANOTHER_DEVICE.HEADER
)
)
.then(testIsBrowserNotified('fxaccounts:login'));
},
},
});
registerSuite('Firefox Desktop non-sync - CWTS on signup', {
beforeEach: function () {
email = createEmail('signuppasswordcwts.{id}');
return this.remote.then(clearBrowserState());
},
tests: {
'signup with no service - do not sync': function () {
return (
this.remote
.then(
openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.SYNC_DESCRIPTION, {
query: {
forceUA: uaStrings['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:can_link_account': { ok: true },
'fxaccounts:fxa_status': {
signedInUser: null,
clientId: FIREFOX_CLIENT_ID,
capabilities: CAPABILITIES,
},
},
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.AGE, 21))
// deselect all the sync engines
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_ADDONS))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_BOOKMARKS))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_HISTORY))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_PASSWORDS))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_PREFS))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_TABS))
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(
testIsBrowserNotified('fxaccounts:login', (event) => {
assert.deepEqual(event.data.services, {});
})
)
);
},
'signup with no service - sync': function () {
return this.remote
.then(
openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.SYNC_DESCRIPTION, {
query: {
forceUA: uaStrings['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:can_link_account': { ok: true },
'fxaccounts:fxa_status': {
signedInUser: null,
clientId: FIREFOX_CLIENT_ID,
capabilities: CAPABILITIES,
},
},
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.AGE, 21))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_BOOKMARKS))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_HISTORY))
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(
testIsBrowserNotified('fxaccounts:login', (event) => {
assert.deepEqual(event.data.services, {
sync: {
declinedEngines: ['bookmarks', 'history'],
offeredEngines: [
'bookmarks',
'history',
'passwords',
'addons',
'tabs',
'prefs',
],
},
});
})
);
},
},
});

Просмотреть файл

@ -1,324 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
const config = intern._config;
const userAgent = uaStrings['desktop_firefox_58'];
const FORCE_AUTH_PAGE_URL = `${
config.fxaContentRoot
}force_auth?forceUA=${encodeURIComponent(userAgent)}`;
const SYNC_FORCE_AUTH_PAGE_URL = `${FORCE_AUTH_PAGE_URL}&service=sync`;
const ENTER_EMAIL_PAGE_URL = `${
config.fxaContentRoot
}?forceUA=${encodeURIComponent(userAgent)}`;
const SYNC_ENTER_EMAIL_PAGE_URL = `${ENTER_EMAIL_PAGE_URL}&service=sync`;
const SETTINGS_PAGE_URL = `${
config.fxaContentRoot
}settings?forceUA=${encodeURIComponent(userAgent)}`;
var browserSignedInEmail;
let browserSignedInAccount;
let otherEmail;
let otherAccount;
const PASSWORD = '12345678';
const {
click,
clearBrowserState,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
testElementExists,
testElementTextEquals,
testElementValueEquals,
thenify,
} = FunctionalHelpers;
const ensureUsers = thenify(function () {
return this.parent
.then(() => {
if (!browserSignedInAccount) {
browserSignedInEmail = createEmail();
return this.parent
.then(
createUser(browserSignedInEmail, PASSWORD, { preVerified: true })
)
.then((_browserSignedInAccount) => {
browserSignedInAccount = _browserSignedInAccount;
browserSignedInAccount.email = browserSignedInEmail;
browserSignedInAccount.verified = true;
});
}
})
.then(() => {
if (!otherAccount) {
otherEmail = createEmail();
return this.parent
.then(createUser(otherEmail, PASSWORD, { preVerified: true }))
.then((_otherAccount) => {
otherAccount = _otherAccount;
otherAccount.email = otherEmail;
otherAccount.verified = true;
});
}
});
});
registerSuite('Firefox desktop user info handshake', {
beforeEach: function () {
return this.remote
.then(clearBrowserState({ forceAll: true }))
.then(ensureUsers());
},
tests: {
'Sync - user signed into browser, no user signed in locally': function () {
return this.remote
.then(
openPage(
SYNC_ENTER_EMAIL_PAGE_URL,
selectors.SIGNIN_PASSWORD.HEADER,
{
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
}
)
)
.then(
testElementValueEquals(
selectors.SIGNIN_PASSWORD.EMAIL,
browserSignedInEmail
)
);
},
'Non-Sync - user signed into browser, no user signed in locally': function () {
return this.remote
.then(
openPage(ENTER_EMAIL_PAGE_URL, selectors.SIGNIN_PASSWORD.HEADER, {
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
})
)
.then(
testElementValueEquals(
selectors.SIGNIN_PASSWORD.EMAIL,
browserSignedInEmail
)
)
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
browserSignedInEmail
)
)
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'Non-Sync - user signed into browser, user signed in locally': function () {
return (
this.remote
// First, sign in the user to populate localStorage
.then(
openPage(ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
},
},
})
)
.then(fillOutEmailFirstSignIn(otherEmail, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
// Then, sign in the user again, synthesizing the user having signed
// into Sync after the initial sign in.
.then(
openPage(ENTER_EMAIL_PAGE_URL, selectors.SIGNIN_PASSWORD.HEADER, {
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
})
)
// browser's view of the world takes precedence, it signed in last
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
browserSignedInEmail
)
)
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'Sync - no user signed into browser, no user signed in locally': function () {
return this.remote
.then(openPage(SYNC_ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, ''));
},
'Sync - no user signed into browser, user signed in locally': function () {
return (
this.remote
// First, sign in the user to populate localStorage
.then(openPage(ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(otherEmail, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
SYNC_ENTER_EMAIL_PAGE_URL,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, otherEmail)
)
);
},
'Non-Sync - no user signed into browser, no user signed in locally': function () {
return this.remote
.then(
openPage(ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
},
},
})
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, ''));
},
'Sync force_auth page - user signed into browser is different to requested user': function () {
return this.remote
.then(
openPage(
`${SYNC_FORCE_AUTH_PAGE_URL}&email=${encodeURIComponent(
otherEmail
)}`,
selectors.FORCE_AUTH.HEADER,
{
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
}
)
)
.then(testElementValueEquals(selectors.FORCE_AUTH.EMAIL, otherEmail));
},
'Non-Sync force_auth page - user signed into browser is different to requested user': function () {
return this.remote
.then(
openPage(
`${FORCE_AUTH_PAGE_URL}&email=${encodeURIComponent(otherEmail)}`,
selectors.FORCE_AUTH.HEADER,
{
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
}
)
)
.then(testElementValueEquals(selectors.FORCE_AUTH.EMAIL, otherEmail));
},
// TODO: These tests are dependent on the changes in #8244
//
/*
'Sync settings page - user signed into browser': function () {
return this.remote
.then(
openPage(SYNC_SETTINGS_PAGE_URL, selectors.SETTINGS.HEADER, {
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
})
)
.then(
testElementTextEquals(
selectors.SETTINGS.PROFILE_HEADER,
browserSignedInEmail
)
);
},
'Non-Sync settings page - user signed into browser': function () {
return this.remote
.then(
openPage(SETTINGS_PAGE_URL, selectors.SETTINGS.HEADER, {
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
})
)
.then(
testElementTextEquals(
selectors.SETTINGS.PROFILE_HEADER,
browserSignedInEmail
)
);
},
'Sync settings page - no user signed into browser': function () {
return this.remote.then(
openPage(SYNC_SETTINGS_PAGE_URL, selectors.ENTER_EMAIL.HEADER)
);
},
'Non-Sync settings page - no user signed into browser, no user signed in locally': function () {
return this.remote.then(
openPage(SETTINGS_PAGE_URL, selectors.ENTER_EMAIL.HEADER)
);
},
*/
'Non-Sync settings page - no user signed into browser, user signed in locally': function () {
return this.remote
.then(openPage(ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(otherEmail, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(SETTINGS_PAGE_URL, selectors.SETTINGS.HEADER))
.then(
testElementTextEquals(selectors.SETTINGS.PROFILE_HEADER, otherEmail)
);
},
},
});

Просмотреть файл

@ -1,70 +0,0 @@
/* eslint-disable camelcase */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const FORCE_AUTH_PAGE_URL = `${config.fxaContentRoot}force_auth?context=fx_firstrun_v2&service=sync`;
const SIGNIN_PAGE_URL = `${config.fxaContentRoot}signin?context=fx_firstrun_v2&service=sync`;
const SIGNUP_PAGE_URL = `${config.fxaContentRoot}signin?context=fx_firstrun_v2&service=sync`;
const RESET_PASSWORD_PAGE_URL = `${config.fxaContentRoot}reset_password?context=fx_firstrun_v2&service=sync`;
const {
clearBrowserState,
click,
openPage,
testElementExists,
} = FunctionalHelpers;
registerSuite('Firefox Desktop first-run v2', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ force: true }));
},
afterEach: function () {
return this.remote.execute(() => {
// Opening about:blank aborts the Firefox download
// and prevents the tests from stalling when run on CentOS
window.location.href = 'about:blank';
});
},
tests: {
force_auth: function () {
return this.remote
.then(openPage(FORCE_AUTH_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
signin: function () {
return this.remote
.then(openPage(SIGNIN_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
signup: function () {
return this.remote
.then(openPage(SIGNUP_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
reset_password: function () {
return this.remote
.then(
openPage(RESET_PASSWORD_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER)
)
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
},
});

Просмотреть файл

@ -1,174 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const FxDesktopHelpers = require('./lib/fx-desktop');
const selectors = require('./lib/selectors');
const UA_STRINGS = require('./lib/ua-strings');
const config = intern._config;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_ios_v1&service=sync`;
const SIGNIN_URL = `${config.fxaContentRoot}signin?context=fx_ios_v1&service=sync`;
let email;
const PASSWORD = '12345678';
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
fillOutSignInTokenCode,
fillOutSignInUnblock,
noPageTransition,
openPage,
testElementExists,
testElementTextInclude,
testElementValueEquals,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
const {
listenForFxaCommands,
testIsBrowserNotifiedOfMessage: testIsBrowserNotified,
testIsBrowserNotifiedOfLogin,
} = FxDesktopHelpers;
const setupTest = thenify(function (options = {}) {
const successSelector = options.blocked
? selectors.SIGNIN_UNBLOCK.HEADER
: options.preVerified
? selectors.SIGNIN_TOKEN_CODE.HEADER
: selectors.CONFIRM_SIGNUP_CODE.HEADER;
return this.parent
.then(createUser(email, PASSWORD, { preVerified: options.preVerified }))
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: options.query,
})
)
.execute(listenForFxaCommands)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(successSelector))
.then(testIsBrowserNotified('can_link_account'));
});
registerSuite('FxiOS v1 signin', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'open directly to /signin page': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
// redirected immediately to the / page
.then(openPage(SIGNIN_URL, selectors.ENTER_EMAIL.HEADER))
);
},
verified: function () {
const forceUA = UA_STRINGS['ios_firefox_6_1'];
const query = { forceUA };
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, { query })
)
.execute(listenForFxaCommands)
.then(visibleByQSA(selectors.ENTER_EMAIL.SYNC_DESCRIPTION))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(testIsBrowserNotified('can_link_account'))
// user thinks they mistyped their email
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(testElementExists(selectors.SIGNIN_PASSWORD.SHOW_PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.SIGNIN_TOKEN_CODE.HEADER
)
)
.then(fillOutSignInTokenCode(email, 0))
.then(testIsBrowserNotifiedOfLogin(email, { expectVerified: false }))
.then(testElementExists(selectors.SIGNIN_COMPLETE.HEADER))
);
},
unverified: function () {
const forceUA = UA_STRINGS['ios_firefox_6_1'];
const query = { forceUA };
return (
this.remote
.then(setupTest({ preVerified: false, query }))
// email 0 - initial sign up email
// email 1 - sign in w/ unverified address email
// email 2 - "You have verified your Firefox Account"
.then(fillOutSignInTokenCode(email, 1, { query }))
// In Fx for iOS >= 6.1, user should redirect to the signup-complete
// page after verification.
.then(testElementExists(selectors.SIGNUP_COMPLETE.HEADER))
);
},
'blocked, valid code entered': function () {
email = createEmail('block{id}');
const forceUA = UA_STRINGS['ios_firefox_6_1'];
const query = { forceUA };
return (
this.remote
.then(setupTest({ blocked: true, preVerified: true, query }))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.EMAIL_FIELD, email)
)
.then(fillOutSignInUnblock(email, 0))
// about:accounts will take over post-unblock, no transition
.then(noPageTransition(selectors.SIGNIN_UNBLOCK.HEADER))
.then(testIsBrowserNotifiedOfLogin(email, { expectVerified: true }))
);
},
},
});

Просмотреть файл

@ -1,86 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const FxDesktopHelpers = require('./lib/fx-desktop');
const UA_STRINGS = require('./lib/ua-strings');
const selectors = require('./lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_ios_v1&service=sync`;
const SIGNUP_URL = `${config.fxaContentRoot}signup?context=fx_ios_v1&service=sync`;
let email;
const PASSWORD = 'password12345678';
const {
click,
clearBrowserState,
createEmail,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
openPage,
testElementExists,
testEmailExpected,
} = FunctionalHelpers;
const { listenForFxaCommands, testIsBrowserNotifiedOfLogin } = FxDesktopHelpers;
registerSuite('FxiOS v1 sign_up', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState());
},
tests: {
'open directly to /signup page': function () {
return (
this.remote
// redirected immediately to the / page
.then(openPage(SIGNUP_URL, selectors.ENTER_EMAIL.HEADER))
);
},
'sign up + CWTS, verify same browser': function () {
return (
this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: UA_STRINGS['ios_firefox_11_0'],
},
})
)
.execute(listenForFxaCommands)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// In Fx for iOS >= 11.0, user should be transitioned to the
// choose what to Sync page
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
// uncheck the passwords and history engines
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_PASSWORDS))
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_HISTORY))
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.SUBMIT))
// user should be transitioned to the "go confirm your address" page
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// the login message is only sent after the sync preferences screen
// has been cleared.
.then(testIsBrowserNotifiedOfLogin(email))
// verify the user
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SIGNUP_COMPLETE.HEADER))
// A post-verification email should be sent, this is Sync.
.then(testEmailExpected(email, 1))
);
},
},
});

Просмотреть файл

@ -1,71 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const FunctionalHelpers = require('./lib/helpers');
var url = intern._config.fxaContentRoot + 'legal';
var openPage = FunctionalHelpers.openPage;
registerSuite('legal', {
'start at legal page': function () {
return (
this.remote
.then(openPage(url, '#fxa-legal-header'))
.findByCssSelector('a[href="/legal/terms"]')
.click()
.end()
// success is going to the TOS screen
.findByCssSelector('#fxa-tos-back')
.click()
.end()
.findByCssSelector('a[href="/legal/privacy"]')
.click()
.end()
.findByCssSelector('#fxa-pp-back')
.click()
.end()
// success is going back to the legal screen.
.findByCssSelector('#fxa-legal-header')
.end()
);
},
'start at terms page': function () {
return this.remote
.then(openPage(url + '/terms', '#fxa-tos-header'))
.then(FunctionalHelpers.visibleByQSA('#legal-copy[data-shown]'))
.findByCssSelector('#legal-copy[data-shown]')
.getVisibleText()
.then(function (resultText) {
// the legal text shouldn't be empty
assert.ok(resultText.trim().length);
})
.end();
},
'start at privacy page': function () {
return this.remote
.then(openPage(url + '/privacy', '#fxa-pp-header'))
.then(FunctionalHelpers.visibleByQSA('#legal-copy[data-shown]'))
.findByCssSelector('#legal-copy[data-shown]')
.getVisibleText()
.then(function (resultText) {
// the legal text shouldn't be empty
assert.ok(resultText.trim().length);
})
.end();
},
});

Просмотреть файл

@ -1,106 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const assert = intern.getPlugin('chai').assert;
/**
* Listens for FirefoxAccountsCommand events coming from FxA and
* automatically responds so that no error messages are displayed
* and the flows can complete.
*
* Run in the context of the web page.
*/
function listenForFxaCommands() {
// postMessage back responses to the browser so that no error messages
// are displayed and the flows can be completed. Mirrors how the browser
// handles things in
// http://mxr.mozilla.org/mozilla-central/source/browser/base/content/aboutaccounts/aboutaccounts.js#252
function sendMessageToFxa(content) {
window.postMessage(
{
content: content,
type: 'message',
},
'*'
);
}
// Add an event listener that auto responds to FirefoxAccountsCommands so
// that flows can complete and no error messages are displayed.
window.addEventListener('FirefoxAccountsCommand', function (e) {
var command = e.detail.command;
// the firefox Selenium driver does not support querying
// localStorage, and data appended to the URL is overwritten
// when the router updates a route. Waiting for cookies to be
// set is difficult, and selenium is great at searching for
// DOM elements. Append an element every time a FirefoxAccountsCommand
// is received that Selenium can look for to see if the message was
// actually received.
var element = document.createElement('div');
element.setAttribute('id', 'message-' + command);
element.innerText = JSON.stringify(e.detail.data);
document.body.appendChild(element);
var DOES_NOT_RESPOND = ['loaded', 'change_password', 'delete_account'];
if (DOES_NOT_RESPOND.indexOf(command) === -1) {
sendMessageToFxa({
status: command,
});
}
});
return true;
}
/**
* Test if the browser has been notified of a CustomEvent login message.
*
* @param {string} email
* @param {object} [options]
* @param {boolean} [options.expectVerified] - expected user verification status.
* Defaults to `false`
* @returns {promise}
*/
function testIsBrowserNotifiedOfLogin(email, options) {
return function () {
options = options || {};
return this.parent
.findByCssSelector('#message-login')
.getProperty('innerText')
.then((innerText) => {
options = options || {};
var data = JSON.parse(innerText);
assert.equal(data.email, email);
assert.ok(data.unwrapBKey);
assert.ok(data.keyFetchToken);
if (options.expectVerified) {
assert.isTrue(data.verified);
} else {
assert.isFalse(data.verified);
}
})
.end();
};
}
/**
* Test if the browser has been notified of a CustomEvent message
*
* @param {string} message message to expect
* @returns {promise} rejects if message has not been sent.
*/
function testIsBrowserNotifiedOfMessage(message) {
return function () {
return this.parent.findByCssSelector('#message-' + message).end();
};
}
module.exports = {
listenForFxaCommands: listenForFxaCommands,
testIsBrowserNotifiedOfLogin: testIsBrowserNotifiedOfLogin,
testIsBrowserNotifiedOfMessage: testIsBrowserNotifiedOfMessage,
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,26 +0,0 @@
/*eslint-disable max-len, camelcase */
module.exports = {
android_chrome:
'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
android_firefox:
'Mozilla/5.0 (Android 4.4; Mobile; rv:43.0) Gecko/41.0 Firefox/43.0',
desktop_chrome:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.59 Safari/537.36',
desktop_firefox_58:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0',
desktop_firefox_71:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:71.0) Gecko/20100101 Firefox/71.0',
ios_firefox:
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4',
ios_firefox_11_0:
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/11.0 Mobile/12F69 Safari/600.1.4',
ios_firefox_6_1:
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/6.1 Mobile/12F69 Safari/600.1.4',
ios_firefox_9:
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/9.0 Mobile/12F69 Safari/600.1.4',
ios_firefox_10:
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/10.0 Mobile/12F69 Safari/600.1.4', // eslint-disable-line
ios_safari:
'Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3',
};
/*eslint-enable max-len*/

Просмотреть файл

@ -1,74 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
var ERROR_COLOR = '\x1b[1;31m'; // red
var DESCRIPTION_COLOR = '\x1b[1;36m'; // cyan
var DEFAULT_COLOR = '\x1b[0;0m'; // off
function errorColor(text) {
return ERROR_COLOR + text + DEFAULT_COLOR;
}
function descriptionColor(text) {
return DESCRIPTION_COLOR + text + DEFAULT_COLOR;
}
var url = intern._config.fxaContentRoot + 'tests/index.html';
var MOCHA_LOADER_SLEEP = 50;
registerSuite('mocha tests', {
'run the mocha tests': function () {
var self = this;
// timeout after 300 seconds
this.timeout = 300000;
return (
this.remote
.setFindTimeout(this.timeout)
.get(url)
.refresh()
// let the mocha reporter load up
.sleep(MOCHA_LOADER_SLEEP)
// wait for the tests to complete
.findById('total-failures')
.getVisibleText()
.then(function (text) {
if (text !== '0') {
return (
self.remote
// print the errors to the console
.findAllByCssSelector('.fail')
.then(function (elements) {
return Promise.all(
elements.map(function (element) {
return element
.getVisibleText()
.then(function (errorText) {
var parts = errorText.split('‣');
console.error(
errorColor('Failed test: ' + parts[0].trim())
);
console.error(
descriptionColor(' => ' + parts[1].trim())
);
});
})
);
})
.end()
.then(function () {
throw new Error('Expected 0 mocha test failures');
})
);
}
})
.end()
);
},
});

Просмотреть файл

@ -1,107 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
var config = intern._config;
var OAUTH_APP = config.fxaOAuthApp;
const {
clearBrowserState,
createEmail,
createUser,
fillOutEmailFirstSignUp,
fillOutForceAuth,
fillOutSignInUnblock,
fillOutSignUpCode,
openFxaFromRp,
testElementDisabled,
testElementExists,
testElementTextInclude,
testElementValueEquals,
testUrlEquals,
visibleByQSA,
} = FunctionalHelpers;
const PASSWORD = 'password123456789';
let email;
registerSuite('oauth force_auth', {
beforeEach: function () {
email = createEmail();
return this.remote.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
tests: {
'with a registered email': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromRp('force-auth', { query: { email: email } }))
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
// redirected back to the App
.then(testUrlEquals(OAUTH_APP))
);
},
'with an unregistered email': function () {
// Test often times out waiting for emails, give it a bit more time.
// See #5024
this.timeout = 60 * 1000;
return (
this.remote
.then(
openFxaFromRp('force-auth', {
header: selectors.SIGNUP_PASSWORD.HEADER,
query: { email: email },
})
)
.then(visibleByQSA(selectors.SIGNUP_PASSWORD.ERROR))
.then(
testElementTextInclude(selectors.SIGNUP_PASSWORD.ERROR, 'recreate')
)
// ensure the email is filled in, and not editible.
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
.then(testElementDisabled(selectors.SIGNUP_PASSWORD.EMAIL))
.then(fillOutEmailFirstSignUp(email, PASSWORD, { enterEmail: false }))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
// redirected back to the App
.then(testUrlEquals(OAUTH_APP))
);
},
'verified, blocked': function () {
email = createEmail('blocked{id}');
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromRp('force-auth', { query: { email: email } }))
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(fillOutSignInUnblock(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
// redirected back to the App
.then(testUrlEquals(OAUTH_APP))
);
},
},
});

Просмотреть файл

@ -1,166 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
const userAgent = uaStrings['desktop_firefox_58'];
var browserSignedInEmail;
let browserSignedInAccount;
let otherEmail;
let otherAccount;
const PASSWORD = '12345678';
const {
click,
clearBrowserState,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openFxaFromRp,
testElementTextEquals,
thenify,
visibleByQSA,
} = FunctionalHelpers;
const ensureUsers = thenify(function () {
return this.parent
.then(() => {
if (!browserSignedInAccount) {
browserSignedInEmail = createEmail();
return this.parent
.then(
createUser(browserSignedInEmail, PASSWORD, { preVerified: true })
)
.then((_browserSignedInAccount) => {
browserSignedInAccount = _browserSignedInAccount;
browserSignedInAccount.email = browserSignedInEmail;
browserSignedInAccount.verified = true;
});
}
})
.then(() => {
if (!otherAccount) {
otherEmail = createEmail();
return this.parent
.then(createUser(otherEmail, PASSWORD, { preVerified: true }))
.then((_otherAccount) => {
otherAccount = _otherAccount;
otherAccount.email = otherEmail;
otherAccount.verified = true;
});
}
});
});
registerSuite('Firefox desktop user info handshake - OAuth flows', {
beforeEach: function () {
return this.remote
.then(clearBrowserState({ forceAll: true }))
.then(ensureUsers());
},
tests: {
'OAuth signin page - user signed into browser, no user signed in locally': function () {
return (
this.remote
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
forceUA: userAgent,
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
})
)
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
browserSignedInEmail
)
)
// User can sign in with cached credentials, no password needed.
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(
testElementTextEquals(
selectors['123DONE'].AUTHENTICATED,
browserSignedInEmail
)
)
);
},
'OAuth signin page - user signed into browser, user signed in locally': function () {
return (
this.remote
// First, sign in the user to populate localStorage
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
query: {
forceUA: userAgent,
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
},
},
})
)
.then(fillOutEmailFirstSignIn(otherEmail, PASSWORD))
.then(click(selectors['123DONE'].LINK_LOGOUT))
// Wait for the signin button to be visible before
// attempting to refresh the page. If the refresh is
// done before signout has completed, 123done shows
// an alert box which blocks the rest of the text.
.then(visibleByQSA(selectors['123DONE'].BUTTON_SIGNIN))
// Then, sign in the user again, synthesizing the user having signed
// into Sync after the initial sign in.
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
forceUA: userAgent,
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: browserSignedInAccount,
},
},
})
)
// browser's view of the world takes precedence, it signed in last.
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
browserSignedInEmail
)
)
// User can sign in with cached credentials, no password needed.
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(
testElementTextEquals(
selectors['123DONE'].AUTHENTICATED,
browserSignedInEmail
)
)
);
},
},
});

Просмотреть файл

@ -1,503 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const TIMEOUT = 90 * 1000;
const TRUSTED_OAUTH_APP = config.fxaOAuthApp;
const UNTRUSTED_OAUTH_APP = config.fxaUntrustedOauthApp;
const PASSWORD = 'passwordzxcv';
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?action=email`;
let email;
const {
click,
closeCurrentWindow,
createEmail,
createUser,
fillOutForceAuth,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignInTokenCode,
fillOutSignUpCode,
noSuchElement,
openFxaFromRp: openFxaFromTrustedRp,
openFxaFromUntrustedRp,
openPage,
openSettingsInNewTab,
switchToWindow,
testElementExists,
testUrlEquals,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('oauth permissions for untrusted reliers', {
beforeEach: function () {
this.timeout = TIMEOUT;
email = createEmail();
return this.remote.then(
FunctionalHelpers.clearBrowserState({
'321done': true,
contentServer: true,
})
);
},
tests: {
'signin verified': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromUntrustedRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(click(selectors.OAUTH_PERMISSIONS.SUBMIT))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(testUrlEquals(UNTRUSTED_OAUTH_APP));
},
're-signin verified, no additional permissions': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromUntrustedRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testUrlEquals(UNTRUSTED_OAUTH_APP))
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
// user signed in previously and should not need to enter
// either their email address or password
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
// no permissions additional asked for
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
// redirected back to the App without seeing the permissions screen.
.then(testUrlEquals(UNTRUSTED_OAUTH_APP))
);
},
'signin unverified, acts like signup': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: false }))
.then(openFxaFromUntrustedRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
// get the second email, the first was sent on client.signUp w/
// preVerified: false above.
.then(fillOutSignInTokenCode(email, 1))
// user verifies in the same tab, so they are logged in to the RP.
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'signup, verify': function () {
return this.remote
.then(openFxaFromUntrustedRp('enter-email'))
.then(testElementExists(selectors.ENTER_EMAIL.SUB_HEADER))
.getCurrentUrl()
.then(function (url) {
assert.ok(url.indexOf('client_id=') > -1);
assert.ok(url.indexOf('redirect_uri=') > -1);
assert.ok(url.indexOf('state=') > -1);
})
.end()
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED));
},
'signup, then signin with no additional permissions': function () {
return (
this.remote
.then(openFxaFromUntrustedRp('enter-email'))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
// user signed in previously and should not need to enter
// either their email address or password
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(testUrlEquals(UNTRUSTED_OAUTH_APP))
);
},
'signin with new permission available b/c of new account information': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromUntrustedRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
// display name is not available because user has not set their name
.then(
noSuchElement(selectors.OAUTH_PERMISSIONS.CHECKBOX_DISPLAY_NAME)
)
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testUrlEquals(UNTRUSTED_OAUTH_APP))
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(openSettingsInNewTab())
.then(switchToWindow(1))
.then(click(selectors.SETTINGS_DISPLAY_NAME.MENU_BUTTON))
.then(click(selectors.SETTINGS_DISPLAY_NAME.INPUT_LABEL_DISPLAY_NAME))
.then(
type(
selectors.SETTINGS_DISPLAY_NAME.INPUT_DISPLAY_NAME,
'test user'
)
)
.then(click(selectors.SETTINGS_DISPLAY_NAME.SUBMIT))
.then(visibleByQSA(selectors.SETTINGS.SUCCESS))
.then(closeCurrentWindow())
// user is already signed in, does not need to enter their password.
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
// display name is now available
.then(
testElementExists(selectors.OAUTH_PERMISSIONS.CHECKBOX_DISPLAY_NAME)
)
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
);
},
'signin with additional requested permission': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// make display_name available from the start
.then(click(selectors.SETTINGS_DISPLAY_NAME.MENU_BUTTON))
.then(click(selectors.SETTINGS_DISPLAY_NAME.INPUT_LABEL_DISPLAY_NAME))
.then(
type(
selectors.SETTINGS_DISPLAY_NAME.INPUT_DISPLAY_NAME,
'test user'
)
)
// user is already signed in, does not need to enter their password.
.then(click(selectors.SETTINGS_DISPLAY_NAME.SUBMIT))
.then(visibleByQSA(selectors.SETTINGS.SUCCESS))
// the first time through, only request email and uid
.then(
openFxaFromUntrustedRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
scope: 'openid profile:email profile:uid',
},
})
)
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
// display name is not available because it's not requested
.then(
noSuchElement(selectors.OAUTH_PERMISSIONS.CHECKBOX_DISPLAY_NAME)
)
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testUrlEquals(UNTRUSTED_OAUTH_APP))
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
// the second time through, profile:email, profile:uid, and
// profile:display_name will be asked for, so display_name is
// available
.then(
testElementExists(selectors.OAUTH_PERMISSIONS.CHECKBOX_DISPLAY_NAME)
)
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
);
},
'signin after de-selecting a requested permission': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// make display_name available from the start
.then(click(selectors.SETTINGS_DISPLAY_NAME.MENU_BUTTON))
.then(click(selectors.SETTINGS_DISPLAY_NAME.INPUT_LABEL_DISPLAY_NAME))
.then(
type(
selectors.SETTINGS_DISPLAY_NAME.INPUT_DISPLAY_NAME,
'test user'
)
)
.then(click(selectors.SETTINGS_DISPLAY_NAME.SUBMIT))
.then(visibleByQSA(selectors.SETTINGS.SUCCESS))
.then(
openFxaFromUntrustedRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
})
)
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(
testElementExists(selectors.OAUTH_PERMISSIONS.CHECKBOX_DISPLAY_NAME)
)
// deselect display name to ensure permission state is
// saved correctly.
.then(click(selectors.OAUTH_PERMISSIONS.CHECKBOX_DISPLAY_NAME))
.then(
click(
selectors.OAUTH_PERMISSIONS.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(click(selectors['123DONE'].LINK_LOGOUT))
// signin again, no permissions should be asked for even though
// display_name was de-selected last time.
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN,
selectors['123DONE'].AUTHENTICATED
)
)
);
},
},
});
registerSuite('oauth permissions for trusted reliers', {
beforeEach: function () {
email = createEmail();
return this.remote.then(
FunctionalHelpers.clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
tests: {
'signup without `prompt=consent`': function () {
return (
this.remote
.then(openFxaFromTrustedRp('enter-email'))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// no permissions asked for, straight to confirm
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
);
},
'signup with `prompt=consent`': function () {
return (
this.remote
.then(
openFxaFromTrustedRp('enter-email', {
query: { prompt: 'consent' },
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// permissions are asked for with `prompt=consent`
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(click(selectors.OAUTH_PERMISSIONS.SUBMIT))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
);
},
'signin without `prompt=consent`': function () {
return (
this.remote
.then(openFxaFromTrustedRp('enter-email'))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// no permissions asked for, straight to relier
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'signin with `prompt=consent`': function () {
return (
this.remote
.then(
openFxaFromTrustedRp('enter-email', {
query: { prompt: 'consent' },
})
)
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// permissions are asked for with `prompt=consent`
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(click(selectors.OAUTH_PERMISSIONS.SUBMIT))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'signin without `prompt=consent`, then re-signin with `prompt=consent`': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromTrustedRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// no permissions asked for, straight to relier
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(testUrlEquals(TRUSTED_OAUTH_APP))
.then(click(selectors['123DONE'].LINK_LOGOUT))
// currently there is no way to tell when 123done fully logged out
// give the logout request some time to complete
.sleep(1000)
.then(visibleByQSA('#splash .signup'))
// relier changes to request consent
.then(
openFxaFromTrustedRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: { prompt: 'consent' },
})
)
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
// since consent is now requested, user should see prompt
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(click(selectors.OAUTH_PERMISSIONS.SUBMIT))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'force_auth without `prompt=consent`': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openFxaFromTrustedRp('force-auth', { query: { email: email } }))
.then(fillOutForceAuth(PASSWORD))
// no permissions asked for, straight to relier
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'force_auth with `prompt=consent`': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromTrustedRp('force-auth', {
query: {
email: email,
prompt: 'consent',
},
})
)
.then(fillOutForceAuth(PASSWORD))
// permissions are asked for with `prompt=consent`
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(click(selectors.OAUTH_PERMISSIONS.SUBMIT))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
},
});

Просмотреть файл

@ -1,223 +0,0 @@
/* eslint-disable camelcase */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const config = intern._config;
const selectors = require('./lib/selectors');
const EMAIL_FIRST_URL = `${config.fxaContentRoot}?action=email`;
const PASSWORD = 'passwordzxcv';
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
destroySessionForEmail,
fillOutEmailFirstSignIn,
openPage,
openRP,
testElementExists,
testElementTextInclude,
} = FunctionalHelpers;
registerSuite('oauth prompt=none', {
beforeEach: function () {
email = createEmail();
return this.remote.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
afterEach: function () {
return this.remote.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
tests: {
'fails RP that is not allowed': function () {
return this.remote
.then(
openRP({
untrusted: true,
query: { login_hint: email, return_on_error: false },
})
)
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['400'].HEADER))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'prompt=none is not enabled for this client'
)
);
},
'fails if requesting keys': function () {
return this.remote
.then(
openRP({
query: {
client_id: '7f368c6886429f19', // eslint-disable-line camelcase
forceUA:
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36',
keys_jwk:
'eyJrdHkiOiJFQyIsImtpZCI6Im9DNGFudFBBSFZRX1pmQ09RRUYycTRaQlZYblVNZ2xISGpVRzdtSjZHOEEiLCJjcnYiOi' +
'JQLTI1NiIsIngiOiJDeUpUSjVwbUNZb2lQQnVWOTk1UjNvNTFLZVBMaEg1Y3JaQlkwbXNxTDk0IiwieSI6IkJCWDhfcFVZeHpTaldsdX' +
'U5MFdPTVZwamIzTlpVRDAyN0xwcC04RW9vckEifQ',
login_hint: email,
redirect_uri:
'https://mozilla.github.io/notes/fxa/android-redirect.html', // eslint-disable-line camelcase
return_on_error: false,
scope: 'profile https://identity.mozilla.com/apps/notes',
},
})
)
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'prompt=none cannot be used when requesting keys'
)
);
},
'fails if no login_hint': function () {
const email = createEmail();
// We do the session check before the login_hint/id_token_hint check,
// so need a session to generate this error.
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openRP({
query: { return_on_error: false },
})
)
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['400'].HEADER))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'missing oauth parameter'
)
);
},
'fails if no user logged in': function () {
return this.remote
.then(
openRP({
query: {
login_hint: email,
return_on_error: false,
},
})
)
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['400'].HEADER))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'User is not signed in'
)
);
},
'fails if account is not verified': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: false }))
.then(openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(openRP({ query: { login_hint: email, return_on_error: false } }))
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['400'].HEADER))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'Unverified user or session'
)
);
},
'fails if login_hint is different to logged in user': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openRP({
query: { login_hint: createEmail(), return_on_error: false },
})
)
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['400'].HEADER))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'a different user is signed in'
)
);
},
'fails if session is no longer valid': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(destroySessionForEmail(email))
.then(
openRP({
query: { login_hint: email, return_on_error: false },
})
)
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['400'].HEADER))
.then(
testElementTextInclude(
selectors['400'].ERROR,
'User is not signed in'
)
);
},
'succeeds if login_hint same as logged in user': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(EMAIL_FIRST_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openRP({ query: { login_hint: email } }))
.then(click(selectors['123DONE'].BUTTON_PROMPT_NONE))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED));
},
},
});

Просмотреть файл

@ -1,407 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
let TRUSTED_CLIENT_ID;
const TRUSTED_SCOPE = 'profile';
let UNTRUSTED_CLIENT_ID;
const UNTRUSTED_SCOPE = 'profile:uid profile:email';
const UNTRUSTED_NO_VALID_SCOPES = 'profile';
const TRUSTED_REDIRECT_URI = `${config.fxaOAuthApp}api/oauth`;
const UNTRUSTED_REDIRECT_URI = `${config.fxaUntrustedOauthApp}api/oauth`;
const AUTHORIZATION_URL = `${config.fxaContentRoot}authorization`;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}oauth/`;
const {
clearBrowserState,
getQueryParamValue,
openFxaFromRp,
openFxaFromUntrustedRp,
openPage,
testElementTextInclude,
thenify,
} = FunctionalHelpers;
var openPageWithQueryParams = thenify(function (query, expectedHeader) {
return this.parent.then(openPage(ENTER_EMAIL_URL, expectedHeader, { query }));
});
var openEmailFirstExpect200 = thenify(function (queryParams) {
return this.parent.then(
openPageWithQueryParams(queryParams, selectors.ENTER_EMAIL.HEADER)
);
});
var openEmailFirstExpect400 = thenify(function (queryParams) {
return this.parent.then(
openPageWithQueryParams(queryParams, selectors['400'].HEADER)
);
});
const openAuthorizationWithQueryParams = thenify(function (
query,
expectedHeader
) {
return this.parent.then(
openPage(AUTHORIZATION_URL, expectedHeader, { query })
);
});
var testErrorInclude = function (expected) {
return testElementTextInclude('.error', expected);
};
/*eslint-disable camelcase */
registerSuite('oauth query parameter validation', {
beforeEach: function () {
return this.remote
.then(
clearBrowserState({
forceAll: true,
})
)
.then(openFxaFromRp('enter-email'))
.then(getQueryParamValue('client_id'))
.then(function (clientId) {
TRUSTED_CLIENT_ID = clientId;
})
.then(openFxaFromUntrustedRp('enter-email'))
.then(getQueryParamValue('client_id'))
.then(function (clientId) {
UNTRUSTED_CLIENT_ID = clientId;
});
},
tests: {
'service specified': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
service: 'sync',
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('service'));
},
'invalid access_type': function () {
return this.remote
.then(
openEmailFirstExpect400({
access_type: 'invalid',
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('access_type'));
},
'valid access_type (offline)': function () {
return this.remote.then(
openEmailFirstExpect200({
access_type: 'offline',
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
);
},
'valid access_type (online)': function () {
return this.remote.then(
openEmailFirstExpect200({
access_type: 'online',
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
);
},
'missing client_id': function () {
return this.remote
.then(
openEmailFirstExpect400({
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('missing'))
.then(testErrorInclude('client_id'));
},
'empty client_id': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: '',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('client_id'));
},
'space client_id': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: ' ',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('client_id'));
},
'invalid client_id': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: 'invalid_client_id',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('client_id'));
},
'unknown client_id': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: 'deadbeefdeadbeef',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('unknown client'));
},
'empty prompt': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
prompt: '',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('prompt'));
},
'space prompt': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
prompt: ' ',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('prompt'));
},
'invalid prompt': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
prompt: 'invalid',
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('prompt'));
},
'valid prompt (consent)': function () {
return this.remote.then(
openEmailFirstExpect200({
client_id: TRUSTED_CLIENT_ID,
prompt: 'consent',
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
);
},
'invalid redirectTo (url)': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
redirectTo: 'localhost',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('redirectTo'));
},
'valid redirectTo (url)': function () {
return this.remote.then(
openEmailFirstExpect200({
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
redirectTo: 'http://localhost',
scope: TRUSTED_SCOPE,
})
);
},
'invalid redirect_uri (url)': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
redirect_uri: 'localhost',
scope: TRUSTED_SCOPE,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('redirect_uri'));
},
'valid redirect_uri (url)': function () {
return this.remote.then(
openEmailFirstExpect200({
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
);
},
'missing scope': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
})
)
.then(testErrorInclude('missing'))
.then(testErrorInclude('scope'));
},
'empty scope': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
scope: '',
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('scope'));
},
'space scope': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: TRUSTED_CLIENT_ID,
scope: ' ',
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('scope'));
},
'no valid scopes (untrusted)': function () {
return this.remote
.then(
openEmailFirstExpect400({
client_id: UNTRUSTED_CLIENT_ID,
redirect_uri: UNTRUSTED_REDIRECT_URI,
scope: UNTRUSTED_NO_VALID_SCOPES,
})
)
.then(testErrorInclude('invalid'))
.then(testErrorInclude('scope'));
},
'valid scope (trusted)': function () {
return this.remote.then(
openEmailFirstExpect200({
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
})
);
},
'valid scope (untrusted)': function () {
return this.remote.then(
openEmailFirstExpect200({
client_id: UNTRUSTED_CLIENT_ID,
redirect_uri: UNTRUSTED_REDIRECT_URI,
scope: UNTRUSTED_SCOPE,
})
);
},
'authorization with no action (trusted)': function () {
return this.remote.then(
openAuthorizationWithQueryParams(
{
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
},
selectors.ENTER_EMAIL.HEADER
)
);
},
'authorization with force_auth with no email (trusted)': function () {
return (
this.remote
// 400s because there is no email set
.then(
openAuthorizationWithQueryParams(
{
action: 'force_auth',
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
},
selectors['400'].HEADER
)
)
);
},
'authorization with unknown action (trusted)': function () {
return (
this.remote
// 400s because there is no email set
.then(
openAuthorizationWithQueryParams(
{
action: 'unknown',
client_id: TRUSTED_CLIENT_ID,
redirect_uri: TRUSTED_REDIRECT_URI,
scope: TRUSTED_SCOPE,
},
selectors['400'].HEADER
)
)
);
},
},
});
/*eslint-enable camelcase */

Просмотреть файл

@ -1,162 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const FunctionalHelpers = require('./lib/helpers');
const config = intern._config;
const OAUTH_APP = config.fxaOAuthApp;
const selectors = require('./lib/selectors');
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?action=email`;
const PASSWORD = 'passwordzxcv';
let email;
const {
clearBrowserState,
click,
confirmTotpCode,
createEmail,
createUser,
enableTotpInline,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
generateTotpCode,
openFxaFromRp,
openPage,
testElementExists,
testElementTextInclude,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
const testAtOAuthApp = thenify(function () {
return this.parent
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(testElementTextInclude(selectors['123DONE'].AUTHENTICATED_TOTP, '🔒'))
.getCurrentUrl()
.then(function (url) {
// redirected back to the App
assert.ok(url.indexOf(OAUTH_APP) > -1);
});
});
registerSuite('oauth require totp', {
beforeEach: function () {
email = createEmail();
return this.remote.then(
clearBrowserState({
'123done': true,
contentServer: true,
force: true,
})
);
},
tests: {
signup: function () {
return this.remote
.then(
openFxaFromRp('two-step-authentication', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER));
},
'account without TOTP redirects to TOTP setup and completes TOTP flow': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('two-step-authentication', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(enableTotpInline())
.then(testAtOAuthApp());
},
'after enabling TOTP in the login flow, account bypasses TOTP setup on second visit': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('two-step-authentication', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(enableTotpInline())
.then(testAtOAuthApp())
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(visibleByQSA(selectors['123DONE'].BUTTON_SIGNIN))
.then(
openFxaFromRp('two-step-authentication', {
header: selectors.SIGNIN_PASSWORD.HEADER,
})
)
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testAtOAuthApp());
},
'succeed for account with TOTP': function () {
this.timeout = 60 * 1000;
let secret;
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(click(selectors.TOTP.MENU_BUTTON))
.then(click(selectors.TOTP.SHOW_CODE_LINK))
.then(visibleByQSA(selectors.TOTP.MANUAL_CODE))
// Store the secret key to recalculate the code later
.findByCssSelector(selectors.TOTP.MANUAL_CODE)
.getVisibleText()
.then((secretKey) => {
secret = secretKey;
})
.end()
.then(() => this.remote.then(click(selectors.TOTP.KEY_OK_BUTTON)))
.then(() => this.remote.then(confirmTotpCode(secret)))
.then(clearBrowserState({ force: true }))
.then(
openFxaFromRp('two-step-authentication', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
// Correctly submits the totp code and navigates to oauth page
.then(() => {
return this.remote.then(
type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret))
);
})
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(testAtOAuthApp())
);
},
},
});

Просмотреть файл

@ -1,384 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const config = intern._config;
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const PASSWORD = 'passwordzxcv';
const TIMEOUT = 90 * 1000;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?action=email`;
let email;
let secret;
const {
clearBrowserState,
click,
closeCurrentWindow,
createEmail,
createUser,
enableTotp,
fillOutCompleteResetPassword,
fillOutEmailFirstSignIn,
fillOutResetPassword,
generateTotpCode,
openExternalSite,
openFxaFromRp,
openPage,
openPasswordResetLinkInDifferentBrowser,
openVerificationLinkInNewTab,
openVerificationLinkInSameTab,
signOut,
switchToWindow,
testElementExists,
testElementTextInclude,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('oauth reset password', {
beforeEach: function () {
// timeout after 90 seconds
this.timeout = TIMEOUT;
email = createEmail();
return this.remote
.then(
clearBrowserState({
forceAll: true,
})
)
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'reset password, verify same browser': function () {
this.timeout = TIMEOUT;
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD,
selectors.RESET_PASSWORD.HEADER
)
)
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInNewTab(email, 0))
// Complete the reset password in the new tab
.then(switchToWindow(1))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
// this tab's success is seeing the reset password complete header.
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
// user sees the name of the rp, but cannot redirect
.then(
testElementTextInclude(
selectors.RESET_PASSWORD_COMPLETE.SUB_HEADER,
'123done'
)
)
.then(closeCurrentWindow())
// the original tab should automatically sign in
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'reset password, verify same browser with original tab closed':
function () {
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD,
selectors.RESET_PASSWORD.HEADER
)
)
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
// user browses to another site.
.then(openExternalSite())
.then(openVerificationLinkInNewTab(email, 0))
.then(switchToWindow(1))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
// switch to the original window
.then(closeCurrentWindow())
);
},
'reset password, verify same browser by replacing the original tab':
function () {
return this.remote
.then(openFxaFromRp('enter-email'))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD,
selectors.RESET_PASSWORD.HEADER
)
)
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 0))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED));
},
"reset password, verify in a different browser, from the original tab's P.O.V.":
function () {
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD,
selectors.RESET_PASSWORD.HEADER
)
)
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openPasswordResetLinkInDifferentBrowser(email, PASSWORD))
// user verified in a new browser, they have to enter
// their updated credentials in the original tab.
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.SUCCESS))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
// user is redirected to RP
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
"reset password, verify in a different browser, from the new browser's P.O.V.":
function () {
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD,
selectors.RESET_PASSWORD.HEADER
)
)
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
// clear all browser state, simulate opening in a new browser
.then(
clearBrowserState({
forceAll: true,
})
)
.then(openVerificationLinkInSameTab(email, 0))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
// user sees the name of the rp, but cannot redirect
.then(testElementTextInclude('.account-ready-service', '123done'))
);
},
},
});
registerSuite('oauth reset password with TOTP', {
beforeEach: function () {
// timeout after 90 seconds
this.timeout = TIMEOUT;
email = createEmail();
return this.remote
.then(
clearBrowserState({
forceAll: true,
})
)
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(enableTotp())
.then((_secret) => {
secret = _secret;
})
.then(signOut())
.then(
clearBrowserState({
forceAll: true,
})
)
.then(
openFxaFromRp('enter-email', { header: selectors.ENTER_EMAIL.HEADER })
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER)
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD,
selectors.RESET_PASSWORD.HEADER
)
)
.then(fillOutResetPassword(email));
},
tests: {
'reset password, verify same browser same tab': function () {
return this.remote
.then(openVerificationLinkInSameTab(email, 2))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(
click(
selectors.TOTP_SIGNIN.SUBMIT,
selectors['123DONE'].AUTHENTICATED_TOTP
)
)
.then(testElementExists(selectors['123DONE'].AUTHENTICATED_TOTP));
},
'reset password, verify same browser different tab': function () {
return this.remote
.then(openVerificationLinkInNewTab(email, 2))
.then(switchToWindow(1))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(
click(
selectors.TOTP_SIGNIN.SUBMIT,
selectors['123DONE'].AUTHENTICATED_TOTP
)
)
.then(switchToWindow(0))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER));
},
"reset password, verify in a different browser, from the original tab's P.O.V.":
function () {
return (
this.remote
.then(openPasswordResetLinkInDifferentBrowser(email, PASSWORD, 2))
// user verified in a new browser, they have to enter
// their password in the original tab.
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.TOTP_SIGNIN.HEADER
)
)
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(
click(
selectors.TOTP_SIGNIN.SUBMIT,
selectors['123DONE'].AUTHENTICATED_TOTP
)
)
);
},
"reset password, verify in a different browser from new browser's P.O.V.":
function () {
return (
this.remote
// clear all browser state, simulate opening in a new browser
.then(clearBrowserState({ forceAll: true }))
.then(openVerificationLinkInSameTab(email, 2))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
// this tab's success is seeing the reset password complete header.
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
);
},
},
});

Просмотреть файл

@ -1,125 +0,0 @@
/* eslint-disable indent */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
var config = intern._config;
var CONTENT_SERVER = config.fxaContentRoot;
var APPS_SETTINGS_URL = CONTENT_SERVER + 'settings#connected-services';
var UNTRUSTED_OAUTH_APP = config.fxaUntrustedOauthApp;
const selectors = require('./lib/selectors');
var PASSWORD = 'password123456789';
const {
clearBrowserState,
click,
closeCurrentWindow,
createEmail,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
noSuchElement,
openFxaFromRp,
openPage,
openTab,
pollUntilGoneByQSA,
switchToWindow,
testElementExists,
} = FunctionalHelpers;
var email;
registerSuite('oauth settings clients', {
beforeEach: function () {
email = createEmail();
return this.remote.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
tests: {
'rp listed in apps, can be deleted': function () {
var self = this;
self.timeout = 90 * 1000;
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
// lists the first client
.then(openPage(APPS_SETTINGS_URL, selectors.SETTINGS_CLIENTS.HEADER))
// sign in into another app
.then(openTab(UNTRUSTED_OAUTH_APP))
.then(switchToWindow(1))
// cannot use the helper method here, the helper method uses $ (jQuery)
// 123Done loads jQuery in the <body> this leads to '$ is undefined' error
// when running tests, because jQuery can be slow to load
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.OAUTH_PERMISSIONS.HEADER))
.then(click(selectors.OAUTH_PERMISSIONS.SUBMIT))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(closeCurrentWindow())
// second app should show up using 'refresh'
.then(click(selectors.SETTINGS_CLIENTS.BUTTON_REFRESH))
.then(
testElementExists(
'[data-testid=settings-connected-service][data-name^="321"]'
)
)
.then(
click(
'[data-testid=settings-connected-service][data-name^="123"] [data-testid=connected-service-sign-out]'
)
)
// wait for the element to be gone or else it's possible for the subsequent
// `click` can fail with a StaleElementReference because click on 123Done's
// button happens, the XHR request takes a bit of time, the reference to the
// 321Done button is fetched, the XHR request completes and updates the DOM,
// making the reference to the 321Done button stale.
.then(
pollUntilGoneByQSA(
'[data-testid=settings-connected-service][data-name^="123"]'
)
)
.then(
click(
'[data-testid=settings-connected-service][data-name^="321"] [data-testid=connected-service-sign-out]'
)
)
.then(pollUntilGoneByQSA(selectors.SETTINGS_CLIENTS.OAUTH_CLIENT))
// the deleted clients should not show up again, this ensures
// that access tokens are deleted along with the refresh tokens.
.then(click(selectors.SETTINGS_CLIENTS.BUTTON_REFRESH))
.then(
pollUntilGoneByQSA(
'[data-testid=settings-connected-service][data-name^="321"]'
)
)
.then(noSuchElement(selectors.SETTINGS_CLIENTS.OAUTH_CLIENT))
);
},
},
});

Просмотреть файл

@ -1,706 +0,0 @@
/* eslint-disable camelcase */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const FunctionalHelpers = require('./lib/helpers');
const config = intern._config;
const OAUTH_APP = config.fxaOAuthApp;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?action=email`;
const otplib = require('otplib');
const selectors = require('./lib/selectors');
// Default options for TOTP
otplib.authenticator.options = { encoding: 'hex' };
const SETTINGS_URL = `${config.fxaContentRoot}settings`;
const PASSWORD = 'passwordzxcv';
const CODE_CHALLENGE = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM';
const CODE_CHALLENGE_METHOD = 'S256';
let email;
let secret;
const thenify = FunctionalHelpers.thenify;
const {
clearBrowserState,
click,
confirmTotpCode,
createEmail,
createUser,
destroySessionForEmail,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignInUnblock,
fillOutSignInTokenCode,
fillOutSignUpCode,
generateTotpCode,
openFxaFromRp,
openPage,
signOut,
testElementExists,
testElementTextEquals,
testElementTextInclude,
testElementValueEquals,
testUrlInclude,
testUrlPathnameEquals,
type,
visibleByQSA,
} = FunctionalHelpers;
const testAtOAuthApp = thenify(function () {
return this.parent
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.getCurrentUrl()
.then(function (url) {
// redirected back to the App
assert.ok(url.indexOf(OAUTH_APP) > -1);
});
});
registerSuite('oauth signin', {
beforeEach: function () {
email = createEmail();
return this.remote.then(
FunctionalHelpers.clearBrowserState({
forceAll: true,
})
);
},
tests: {
verified: function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testAtOAuthApp());
},
'verified using a cached login': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
// sign in with a verified account to cache credentials
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testAtOAuthApp())
.then(
click(
selectors['123DONE'].LINK_LOGOUT,
selectors['123DONE'].BUTTON_SIGNIN
)
)
.then(visibleByQSA(selectors['123DONE'].BUTTON_SIGNIN))
// round 2 - with the cached credentials
.then(
click(
selectors['123DONE'].BUTTON_SIGNIN,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testAtOAuthApp())
);
},
'verified using a cached expired login': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
// sign in with a verified account to cache credentials
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testAtOAuthApp())
.then(
click(
selectors['123DONE'].LINK_LOGOUT,
selectors['123DONE'].BUTTON_SIGNIN
)
)
.then(visibleByQSA(selectors['123DONE'].BUTTON_SIGNIN))
// round 2 - with the cached credentials
.then(
click(
selectors['123DONE'].BUTTON_SIGNIN,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(destroySessionForEmail(email))
.then(
testElementTextInclude(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
// we only know the sessionToken is expired once the
// user submits the form.
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN,
selectors.SIGNIN_PASSWORD.HEADER
)
)
// we now know the sessionToken is expired. Allow the user to sign in
// with their password.
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testAtOAuthApp())
);
},
'cached credentials that expire while on page': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testAtOAuthApp())
.then(click(selectors['123DONE'].LINK_LOGOUT))
// user is signed in, use cached credentials no password is needed
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
})
)
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
.then(destroySessionForEmail(email))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN,
selectors.SIGNIN_PASSWORD.ERROR
)
)
// Session expired error should show.
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.ERROR))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors['123DONE'].AUTHENTICATED
)
)
.then(testAtOAuthApp())
);
},
'unverified, acts like signup': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: false }))
.then(openFxaFromRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// get the second email, the first was sent on client.signUp w/
// preVerified: false above. The second email has the `service` and
// `resume` parameters.
.then(fillOutSignInTokenCode(email, 1))
// user verifies in the same tab, so they are logged in to the RP.
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'unverified with a cached login': function () {
return (
this.remote
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// first, sign the user up to cache the login
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// round 2 - try to sign in with the unverified user.
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
})
)
.then(testElementExists(selectors.SIGNIN_PASSWORD.SUB_HEADER))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
// success is using a cached login and being redirected
// to a confirmation screen
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// get the second email, the first was sent via fillOutEmailFirstSignUp above.
.then(fillOutSignInTokenCode(email, 1))
.then(testAtOAuthApp())
);
},
'oauth endpoint chooses the right auth flows': function () {
return (
this.remote
.then(openPage(OAUTH_APP, '.ready'))
// use the 'Choose my sign-in flow for me' button
.then(click(selectors['123DONE'].BUTTON_SIGNIN_CHOOSE_FLOW_FOR_ME))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// go back to the OAuth app, the /oauth flow should
// now suggest a cached login
.get(OAUTH_APP)
// again, use the 'Choose my sign-in flow for me' button
.then(click(selectors['123DONE'].BUTTON_SIGNIN_CHOOSE_FLOW_FOR_ME))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
);
},
'email specified by relier, invalid': function () {
const invalidEmail = 'invalid@';
return this.remote
.then(
openFxaFromRp('enter-email', {
header: selectors.ENTER_EMAIL.HEADER,
query: {
email: invalidEmail,
},
})
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, invalidEmail))
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP))
.then(
testElementTextEquals(
selectors.ENTER_EMAIL.TOOLTIP,
'Valid email required'
)
);
},
'email specified by relier, not registered': function () {
return (
this.remote
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNUP_PASSWORD.HEADER,
query: {
email,
},
})
)
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
// user realizes it's the wrong email address.
.then(
click(
selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
);
},
'login_hint specified by relier, not registered': function () {
return (
this.remote
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNUP_PASSWORD.HEADER,
query: {
login_hint: email,
},
})
)
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
// user realizes it's the wrong email address.
.then(
click(
selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
);
},
'email specified by relier, registered': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
email,
},
})
)
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
// user realizes it's the wrong email address.
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
);
},
'login_hint specified by relier, registered': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
login_hint: email,
},
})
)
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email));
},
'cached credentials, login_hint specified by relier': function () {
const loginHintEmail = createEmail();
const oAuthEmail = createEmail();
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(createUser(oAuthEmail, PASSWORD, { preVerified: true }))
.then(createUser(loginHintEmail, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('email-first', {
header: selectors.ENTER_EMAIL.HEADER,
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(testAtOAuthApp())
.then(
click(
selectors['123DONE'].LINK_LOGOUT,
selectors['123DONE'].BUTTON_SIGNIN
)
)
// login_hint takes precedence over the signed in user
.then(
openFxaFromRp('email-first', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
login_hint: loginHintEmail,
},
})
)
.then(
testElementValueEquals(
selectors.SIGNIN_PASSWORD.EMAIL,
loginHintEmail
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(testAtOAuthApp())
);
},
'login_hint specified by relier, registered, user changes email':
function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
query: {
login_hint: email,
},
})
)
.then(
testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email)
)
// user realizes they want to use a different account.
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
);
},
'verified, blocked': function () {
email = createEmail('blocked{id}');
return this.remote
.then(openFxaFromRp('enter-email'))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(fillOutSignInUnblock(email, 0))
.then(testAtOAuthApp());
},
'verified, blocked, incorrect password': function () {
email = createEmail('blocked{id}');
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(fillOutEmailFirstSignIn(email, 'bad' + PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(fillOutSignInUnblock(email, 0))
// wait until at the signin page to check the URL to
// avoid latency problems with submitting the unblock code.
// w/o the wait, the URL can be checked before
// the submit completes.
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(testUrlPathnameEquals('/oauth/signin'))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.SIGNIN_UNBLOCK.HEADER
)
)
.then(fillOutSignInUnblock(email, 1))
.then(testAtOAuthApp())
);
},
'signin in Chrome for Android, verify same browser': function () {
// The `sync` prefix is needed to force signin confirmation.
email = createEmail('sync{id}');
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('enter-email', {
query: {
client_id: '7f368c6886429f19', // eslint-disable-line camelcase
code_challenge: CODE_CHALLENGE,
code_challenge_method: CODE_CHALLENGE_METHOD,
forceUA:
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36',
// eslint-disable-next-line camelcase
keys_jwk:
'eyJrdHkiOiJFQyIsImtpZCI6Im9DNGFudFBBSFZRX1pmQ09RRUYycTRaQlZYblVNZ2xISGpVRzdtSjZHOEEiLCJjcnYiOi' +
'JQLTI1NiIsIngiOiJDeUpUSjVwbUNZb2lQQnVWOTk1UjNvNTFLZVBMaEg1Y3JaQlkwbXNxTDk0IiwieSI6IkJCWDhfcFVZeHpTaldsdX' +
'U5MFdPTVZwamIzTlpVRDAyN0xwcC04RW9vckEifQ',
redirect_uri:
'https://mozilla.github.io/notes/fxa/android-redirect.html', // eslint-disable-line camelcase
scope: 'profile https://identity.mozilla.com/apps/notes',
},
})
)
.then(testElementTextInclude(selectors.ENTER_EMAIL.SUB_HEADER, 'notes'))
.then(testUrlInclude('client_id='))
.then(testUrlInclude('state='))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(fillOutSignInTokenCode(email, 0))
.then(testElementExists(selectors.FIREFOX_NOTES.HEADER));
},
},
});
registerSuite('oauth signin - TOTP', {
beforeEach: function () {
email = createEmail();
return (
this.remote
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.TOTP.MENU_BUTTON))
.then(click(selectors.TOTP.MENU_BUTTON))
.then(testElementExists(selectors.TOTP.QR_CODE))
.then(testElementExists(selectors.TOTP.SHOW_CODE_LINK))
.then(click(selectors.TOTP.SHOW_CODE_LINK))
.then(testElementExists(selectors.TOTP.MANUAL_CODE))
// Store the secret key to recalculate the code later
.findByCssSelector(selectors.TOTP.MANUAL_CODE)
.getVisibleText()
.then((secretKey) => {
secret = secretKey;
})
.end()
.then(() => this.remote.then(click(selectors.TOTP.KEY_OK_BUTTON)))
);
},
tests: {
'can add TOTP to account and confirm oauth signin': function () {
return (
this.remote
.then(confirmTotpCode(secret))
.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
)
.then(openFxaFromRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// Correctly submits the totp code and navigates to oauth page
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(testAtOAuthApp())
);
},
'can remove TOTP from account and skip confirmation': function () {
return (
this.remote
.then(confirmTotpCode(secret))
// Remove token
.then(click(selectors.TOTP.DELETE_BUTTON))
.then(click(selectors.TOTP.CONFIRM_DELETE))
.then(testElementExists(selectors.TOTP.DISABLE_SUCCESS))
.then(testElementExists(selectors.TOTP.MENU_BUTTON))
// Does not prompt for code
.then(signOut())
.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
)
.then(openFxaFromRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testAtOAuthApp())
);
},
},
});

Просмотреть файл

@ -1,130 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const assert = intern.getPlugin('chai').assert;
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const PASSWORD = 'passwordzxcv';
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
destroySessionForEmail,
fillOutEmailFirstSignIn,
fillOutSignInTokenCode,
openFxaFromRp,
testElementExists,
testElementTextInclude,
getEmailHeaders,
type,
visibleByQSA,
} = FunctionalHelpers;
const NOTES_REDIRECT_PAGE_SELECTOR = '#notes-by-firefox';
const NOTES_PAGE_TEXT_SELECTOR = 'Notes by Firefox';
const experimentParams = {
query: {
client_id: '7f368c6886429f19', // eslint-disable-line camelcase
code_challenge: 'aSOwsmuRBE1ZIVtiW6bzKMaf47kCFl7duD6ZWAXdnJo', // eslint-disable-line camelcase
code_challenge_method: 'S256', // eslint-disable-line camelcase
forceUA:
'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36',
// eslint-disable-next-line camelcase
keys_jwk:
'eyJrdHkiOiJFQyIsImtpZCI6Im9DNGFudFBBSFZRX1pmQ09RRUYycTRaQlZYblVNZ2xISGpVRzdtSjZHOEEiLCJjcnYiOi' +
'JQLTI1NiIsIngiOiJDeUpUSjVwbUNZb2lQQnVWOTk1UjNvNTFLZVBMaEg1Y3JaQlkwbXNxTDk0IiwieSI6IkJCWDhfcFVZeHpTaldsdX' +
'U5MFdPTVZwamIzTlpVRDAyN0xwcC04RW9vckEifQ',
redirect_uri: 'https://mozilla.github.io/notes/fxa/android-redirect.html', // eslint-disable-line camelcase
scope: 'profile https://identity.mozilla.com/apps/notes',
},
};
registerSuite('OAuth signin token code', {
beforeEach: function () {
// The `sync` prefix is needed to force confirmation.
email = createEmail('sync{id}');
return this.remote
.then(clearBrowserState({ forceAll: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'verified - invalid token': function () {
experimentParams.query.forceExperiment = 'tokenCode';
experimentParams.query.forceExperimentGroup = 'treatment-code';
return (
this.remote
.then(openFxaFromRp('enter-email', experimentParams))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
// This will cause the token become 'invalid' and ultimately cause an
// INVALID_TOKEN error to be thrown.
.then(destroySessionForEmail(email))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
);
},
'verified - valid code': function () {
return (
this.remote
.then(openFxaFromRp('enter-email', experimentParams))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// Displays invalid code errors
.then(type(selectors.SIGNIN_TOKEN_CODE.INPUT, '000000'))
.then(
click(
selectors.SIGNIN_TOKEN_CODE.SUBMIT,
selectors.SIGNIN_TOKEN_CODE.TOOLTIP
)
)
.then(visibleByQSA(selectors.SIGNIN_TOKEN_CODE.TOOLTIP))
.then(
testElementTextInclude(
selectors.SIGNIN_TOKEN_CODE.TOOLTIP,
'Invalid or expired'
)
)
// Can resend code
.then(
click(
selectors.SIGNIN_TOKEN_CODE.LINK_RESEND,
selectors.SIGNIN_TOKEN_CODE.SUCCESS
)
)
.then(
testElementTextInclude(
selectors.SIGNIN_TOKEN_CODE.SUCCESS,
'Email resent.'
)
)
// Correctly submits the token code and navigates to oauth page
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(getEmailHeaders(email, 1))
.then((headers) => {
assert.equal(headers['x-template-name'], 'verifyLoginCode');
})
.then(fillOutSignInTokenCode(email, 1))
.then(testElementExists(NOTES_REDIRECT_PAGE_SELECTOR))
.then(
testElementTextInclude(
NOTES_REDIRECT_PAGE_SELECTOR,
NOTES_PAGE_TEXT_SELECTOR
)
)
);
},
},
});

Просмотреть файл

@ -1,100 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const PASSWORD = 'password12345678';
const SUCCESS_URL = config.fxaContentRoot + 'oauth/success/dcdb5ae7add825d2';
let email;
let bouncedEmail;
const {
clearBrowserState,
createEmail,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
getFxaClient,
noEmailExpected,
openFxaFromRp,
openPage,
testElementExists,
testUrlInclude,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('oauth signup', {
beforeEach: function () {
email = createEmail();
bouncedEmail = createEmail();
// clear localStorage to avoid polluting other tests.
// Without the clear, /signup tests fail because of the info stored
// in prefillEmail
return this.remote.then(
clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
tests: {
signup: function () {
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(testUrlInclude('client_id='))
.then(testUrlInclude('redirect_uri='))
.then(testUrlInclude('state='))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
// Do not expect a post-verification email, those are for Sync.
.then(noEmailExpected(email, 1))
);
},
'signup, bounce email, allow user to restart flow but force a different email':
function () {
return (
this.remote
.then(openFxaFromRp('enter-email'))
.then(fillOutEmailFirstSignUp(bouncedEmail, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(function () {
return getFxaClient().accountDestroy(bouncedEmail, PASSWORD);
})
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// expect an error message to already be present on redirect
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP_BOUNCED_EMAIL))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
);
},
'a success screen is available': function () {
return this.remote.then(
openPage(SUCCESS_URL, '#fxa-oauth-success-header')
);
},
},
});

Просмотреть файл

@ -1,151 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const SYNC_EMAIL_FIRST_URL =
config.fxaContentRoot + '?context=fx_desktop_v3&service=sync&action=email';
let email;
let email2;
const PASSWORD = 'passwordzxcv';
const {
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignInTokenCode,
fillOutSignUpCode,
openFxaFromRp,
openPage,
testElementExists,
testElementTextEquals,
testIsBrowserNotified,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('signin with OAuth after Sync', {
beforeEach: function () {
email = createEmail('sync{id}');
email2 = createEmail();
// clear localStorage to avoid pollution from other tests.
return this.remote.then(
FunctionalHelpers.clearBrowserState({
'123done': true,
contentServer: true,
})
);
},
tests: {
'signin to OAuth with Sync creds': function () {
this.timeout = 60 * 1000;
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(SYNC_EMAIL_FIRST_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
// Sync signins must be verified.
.then(fillOutSignInTokenCode(email, 0))
.then(testIsBrowserNotified('fxaccounts:login'))
// Sign up for a new account via OAuth
.then(
openFxaFromRp('enter-email', {
header: selectors.SIGNIN_PASSWORD.HEADER,
})
)
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(fillOutEmailFirstSignUp(email2, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email2, 0))
// RP is logged in, logout then back in again.
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(visibleByQSA(selectors['123DONE'].BUTTON_SIGNIN))
.then(click(selectors['123DONE'].BUTTON_SIGNIN))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
// By default, we should see the email we signed up for Sync with
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
// no need to enter the password!
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
// We should see the email we signed up for Sync with
.then(
testElementTextEquals(selectors['123DONE'].AUTHENTICATED, email)
)
);
},
},
});
registerSuite('signin to Sync after OAuth', {
beforeEach: function () {
email = createEmail('sync{id}');
email2 = createEmail();
// clear localStorage to avoid pollution from other tests.
return this.remote.then(
FunctionalHelpers.clearBrowserState({
'123done': true,
contentServer: true,
force: true,
})
);
},
tests: {
'email-first Sync signin': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openFxaFromRp('email-first', { header: selectors.ENTER_EMAIL.HEADER })
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementTextEquals(selectors['123DONE'].AUTHENTICATED, email))
.then(openPage(SYNC_EMAIL_FIRST_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(fillOutSignInTokenCode(email, 1))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER));
},
},
});

Просмотреть файл

@ -1,78 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
var url = intern._config.fxaContentRoot;
// Commented out pages here likely mean the React version is rolled out to 100%
// and we don't want to check these for `#stage header` selectors.
var pages = [
'',
'authorization',
'boom',
'choose_what_to_sync',
'complete_reset_password',
'complete_signin',
'confirm',
'confirm_reset_password',
'confirm_signin',
'connect_another_device',
'force_auth',
'non_existent',
'oauth',
'oauth/force_auth',
'oauth/signin',
'oauth/signup',
'report_signin',
'reset_password',
'reset_password_confirmed',
'reset_password_complete', // redirects to reset_password_verified
'reset_password_verified',
'settings',
'settings/avatar',
'settings/change_password',
'settings/clients',
'settings/communication_preferences',
'settings/delete_account',
'settings/display_name',
'signin',
'signin_bounced',
'signin_confirmed',
'signin_complete', // redirects to signin_verified
'signin_permissions',
'signin_reported',
'signin_unblock',
'signin_verified',
'signup',
'signup_confirmed',
'signup_complete', // redirects to signup_verified
'signup_permissions',
'signup_verified',
'support',
'verify_email',
'v1/complete_reset_password',
'v1/reset_password',
'v1/verify_email',
];
var suite = {};
var visitFn = function (path) {
return function () {
return this.remote
.get(url + path)
.setFindTimeout(intern._config.pageLoadTimeout)
.findByCssSelector('#stage header')
.end();
};
};
pages.forEach(function (path) {
suite['visit page ' + url + path] = visitFn(path);
suite['visit page ' + url + path + '/'] = visitFn(path + '/');
});
registerSuite('pages', suite);

Просмотреть файл

@ -1,326 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
//const assert = intern.getPlugin('chai').assert;
const selectors = require('./lib/selectors');
const FunctionalHelpers = require('./lib/helpers');
const config = intern._config;
//const QUERY_PARAMS =
('?context=fx_desktop_v3&service=sync&automatedBrowser=true&action=email');
//const SIGNIN_PAGE_URL = `${config.fxaContentRoot}${QUERY_PARAMS}`;
//const REDIRECT_HOST = encodeURIComponent(config.fxaContentRoot);
const BAD_CLIENT_ID = 'dcdb5ae7add825d2';
const BAD_OAUTH_REDIRECT = `${config.fxaOAuthApp}api/oauth`;
//const GOOD_CLIENT_ID = '3c49430b43dfba77';
////const GOOD_PAIR_URL = `${config.fxaContentRoot}pair/supp?response_type=code&client_id=${GOOD_CLIENT_ID}&redirect_uri=${REDIRECT_HOST}oauth%2Fsuccess%2F3c49430b43dfba77&scope=profile%2Bhttps%3A%2F%2Fidentity.mozilla.com%2Fapps%2Foldsync&state=foo&code_challenge_method=S256&code_challenge=IpOAcntLUmKITcxI_rDqMvFTeC9n_g0B8_Pj2yWZp7w&access_type=offline&keys_jwk=eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6ImlmcWY2U1pwMlM0ZjA5c3VhS093dmNsbWJxUm8zZXdGY0pvRURpYnc4MTQiLCJ5IjoiSE9LTXh5c1FseExqRGttUjZZbFpaY1Y4MFZBdk9nSWo1ZHRVaWJmYy1qTSJ9`; //eslint-disable-line max-len
const BAD_PAIR_URL = `${config.fxaContentRoot}pair/supp?response_type=code&client_id=${BAD_CLIENT_ID}&redirect_uri=${BAD_OAUTH_REDIRECT}&scope=profile%2Bhttps%3A%2F%2Fidentity.mozilla.com%2Fapps%2Foldsync&state=foo&code_challenge_method=S256&code_challenge=IpOAcntLUmKITcxI_rDqMvFTeC9n_g0B8_Pj2yWZp7w&access_type=offline&keys_jwk=eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6ImlmcWY2U1pwMlM0ZjA5c3VhS093dmNsbWJxUm8zZXdGY0pvRURpYnc4MTQiLCJ5IjoiSE9LTXh5c1FseExqRGttUjZZbFpaY1Y4MFZBdk9nSWo1ZHRVaWJmYy1qTSJ9`; //eslint-disable-line max-len
//const SETTINGS_URL = `${config.fxaContentRoot}settings`;
const DESKTOP_SIGNUP_URL = `${config.fxaContentRoot}signup?context=fx_desktop_v3&entrypoint=fxa_app_menu&service=sync`;
const PASSWORD = 'PASSWORD123123';
let email;
const {
createUser,
clearBrowserState,
click,
//closeCurrentWindow,
createEmail,
//confirmTotpCode,
enableTotp,
generateTotpCode,
openPage,
//openTab,
//switchToWindow,
type,
//thenify,
testElementTextInclude,
testElementExists,
//testIsBrowserNotified,
} = FunctionalHelpers;
/*function getQrData(buffer) {
return new Promise(function (resolve, reject) {
const jsQR = require('jsqr');
const png = require('upng-js');
try {
const data = png.decode(buffer);
const out = {
data: new Uint8ClampedArray(png.toRGBA8(data)[0]),
height: data.height,
width: data.width,
};
const code = jsQR(out.data, out.width, out.height);
if (code) {
return resolve(code.data);
} else {
return reject('No QR code found');
}
} catch (e) {
return reject('Failed to read QR code', e);
}
});
}*/
/*const waitForQR = thenify(function () {
let requestAttempts = 0;
const maxAttempts = 5;
const parent = this.parent;
function pollForScreenshot() {
return parent
.sleep(1500)
.takeScreenshot()
.then((buffer) => {
return getQrData(buffer)
.then((result) => {
const pairingStuff = result.split('#')[1];
return parent.then(
openTab(
GOOD_PAIR_URL + '#' + pairingStuff,
selectors.ENTER_EMAIL.HEADER
)
);
})
.catch((err) => {
requestAttempts++;
if (requestAttempts >= maxAttempts) {
return Promise.reject(new Error(`QRTimeout: ${err}`));
} else {
return new Promise(function (resolve, reject) {
setTimeout(function () {
pollForScreenshot().then(resolve, reject);
}, 1000);
});
}
});
});
}
return pollForScreenshot();
});*/
registerSuite('pairing', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ force: true }));
},
//disabling this flaky test
tests: {
/*'it can pair': function () {
let secret;
email = createEmail();
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(SIGNIN_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.CONNECT_ANOTHER_DEVICE.HEADER
)
)
// but the login message is sent automatically.
.then(testIsBrowserNotified('fxaccounts:login'))
.then(
openPage(
`${config.fxaContentRoot}pair`,
selectors.PAIRING.START_PAIRING
)
)
.then(click(selectors.PAIRING.START_PAIRING))
.then(waitForQR())
.then(switchToWindow(1))
.then(click(selectors.PAIRING.SUPP_SUBMIT))
.catch((err) => {
if (err.message && err.message.includes('Web element reference')) {
// We have to catch an error here due to https://bugzilla.mozilla.org/show_bug.cgi?id=1422769
// .click still works, but just throws for no reason. We assert below that pairing still works.
} else {
// if this is an unknown error, then we throw
throw err;
}
})
.then(switchToWindow(0))
.then(click(selectors.PAIRING.AUTH_SUBMIT))
.then(switchToWindow(1))
.then(testElementExists(selectors.PAIRING.COMPLETE))
.getCurrentUrl()
.then(function (redirectResult) {
assert.ok(
redirectResult.includes('code='),
'final OAuth redirect has the code'
);
assert.ok(
redirectResult.includes('state='),
'final OAuth redirect has the state'
);
})
.end()
.then(closeCurrentWindow())
.then(openPage(SETTINGS_URL, selectors.TOTP.MENU_BUTTON))
.then(click(selectors.TOTP.MENU_BUTTON))
.then(click(selectors.TOTP.SHOW_CODE_LINK))
.findByCssSelector(selectors.TOTP.MANUAL_CODE)
.getVisibleText()
.then((secretKey) => {
secret = secretKey;
})
.then(() => this.remote.then(click(selectors.TOTP.KEY_OK_BUTTON)))
.then(() => {
return this.remote.then(confirmTotpCode(secret));
})
.end()
.then(
openPage(
`${config.fxaContentRoot}pair`,
selectors.PAIRING.START_PAIRING
)
)
.then(click(selectors.PAIRING.START_PAIRING))
.then(waitForQR())
.then(switchToWindow(1))
.then(click(selectors.PAIRING.SUPP_SUBMIT))
.catch((err) => {
if (err.message && err.message.includes('Web element reference')) {
// We have to catch an error here due to https://bugzilla.mozilla.org/show_bug.cgi?id=1422769
// .click still works, but just throws for no reason. We assert below that pairing still works.
} else {
// if this is an unknown error, then we throw
throw err;
}
})
.then(switchToWindow(0))
.then(() => {
return this.remote.then(
type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret))
);
})
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(click(selectors.PAIRING.AUTH_SUBMIT))
.then(switchToWindow(1))
.then(testElementExists(selectors.PAIRING.COMPLETE))
.getCurrentUrl()
.then(function (redirectResult) {
assert.ok(
redirectResult.includes('code='),
'final OAuth redirect has the code'
);
assert.ok(
redirectResult.includes('state='),
'final OAuth redirect has the state'
);
})
.end()
.then(closeCurrentWindow())
);
},*/
'handles invalid clients': function () {
return this.remote
.then(
openPage(
`${BAD_PAIR_URL}#channel_id=foo&channel_key=bar`,
selectors['400'].ERROR
)
)
.then(
testElementTextInclude(
selectors['400'].ERROR,
'Invalid pairing client'
)
);
},
'it shows qr code after sign in from fx desktop pre': function () {
email = createEmail();
let secret = '';
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(DESKTOP_SIGNUP_URL))
.then(() =>
this.remote.findAllByCssSelector(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT
)
)
.then((r) => r[0]?.click())
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
.then(() => this.remote.sleep(100))
.then(() => this.remote.acceptAlert())
.catch(() => {})
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(selectors.SIGNIN_PASSWORD.SUBMIT, selectors.PAIRING.HEADER)
)
.then(testElementExists(selectors.PAIRING.CONNECT_ANOTHER_QR_CODE))
// also check that this works with 2FA enabled.
.then(enableTotp())
.then((_secret) => {
secret = _secret;
})
.then(openPage(DESKTOP_SIGNUP_URL))
.then(() =>
this.remote.findAllByCssSelector(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT
)
)
.then((r) => r[0]?.click())
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
.then(() => this.remote.sleep(100))
.then(() => this.remote.acceptAlert())
.catch(() => {})
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.TOTP_SIGNIN.HEADER
)
)
// Correctly submits the totp code and navigates to oauth page
.then(() => {
return this.remote.then(
type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret))
);
})
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(testElementExists(selectors.PAIRING.CONNECT_ANOTHER_QR_CODE))
);
},
},
});

Просмотреть файл

@ -1,176 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const PAGE_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync&action=email`; //eslint-disable-line max-len
let email;
const {
clearBrowserState,
click,
createEmail,
openPage,
testElementExists,
type,
} = FunctionalHelpers;
registerSuite('password strength balloon', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote
.then(clearBrowserState({ force: true }))
.then(openPage(PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
);
},
tests: {
'submit w/o a password': function () {
return this.remote
.then(click(selectors.SIGNUP_PASSWORD.SUBMIT))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_FAIL
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_UNMET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_UNMET
)
);
},
'too short of a password': function () {
return this.remote
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, 'p'))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_FAIL
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_UNMET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_UNMET
)
);
},
'password is too common': function () {
return this.remote
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, 'password'))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_MET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_MET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_FAIL
)
);
},
'password is the same as the full email': function () {
return this.remote
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, email))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_MET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_FAIL
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_UNMET
)
);
},
'password is same as the local part of the email': function () {
return this.remote
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, email.split('@')[0]))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_MET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_FAIL
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_UNMET
)
);
},
'good password, then back to too short': function () {
return this.remote
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, 'password123123'))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_MET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_MET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_MET
)
)
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, 'pass'))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_FAIL
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_UNMET
)
)
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_UNMET
)
);
},
},
});

Просмотреть файл

@ -1,94 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const {
clearBrowserState,
click,
createEmail,
mousedown,
noSuchAttribute,
openPage,
testAttributeEquals,
testElementExists,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('password visibility', {
beforeEach: function () {
return this.remote.then(clearBrowserState());
},
tests: {
'show password ended with second mousedown': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, createEmail()))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, 'p'))
.then(testElementExists(selectors.SIGNUP_PASSWORD.SHOW_PASSWORD))
.then(visibleByQSA(selectors.SIGNUP_PASSWORD.SHOW_PASSWORD))
// turn password field into a text field
.then(mousedown(selectors.SIGNUP_PASSWORD.SHOW_PASSWORD))
.then(
testAttributeEquals(
selectors.SIGNUP_PASSWORD.PASSWORD,
'type',
'text'
)
)
.then(
testAttributeEquals(
selectors.SIGNUP_PASSWORD.PASSWORD,
'autocomplete',
'off'
)
)
// turn text field back into a password field
.then(mousedown(selectors.SIGNUP_PASSWORD.SHOW_PASSWORD))
.then(
testAttributeEquals(
selectors.SIGNUP_PASSWORD.PASSWORD,
'type',
'password'
)
)
.then(
noSuchAttribute(selectors.SIGNUP_PASSWORD.PASSWORD, 'autocomplete')
)
// \u0008 is unicode for backspace char. By default `type` clears the
// element value before typing, we want the character to do so.
.then(
type(selectors.SIGNUP_PASSWORD.PASSWORD, '\u0008', {
clearValue: true,
})
)
// give a short pause to clear the input
.sleep(1000)
// element still exists
.then(testElementExists(selectors.SIGNUP_PASSWORD.SHOW_PASSWORD))
);
},
},
});

Просмотреть файл

@ -1,171 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./../lib/helpers');
const selectors = require('./../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const ACCOUNT_RECOVERY_URL =
config.fxaContentRoot + 'post_verify/account_recovery/add_recovery_key';
const PASSWORD = 'password1234567';
let email, recoveryKey;
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
testElementExists,
testElementTextInclude,
testElementTextNotEmpty,
testSuccessWasShown,
testSuccessWasNotShown,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
const getRecoveryKey = thenify(function () {
return (
this.parent
// Extract the account recovery key from form
.findByCssSelector(selectors.POST_VERIFY_SAVE_RECOVERY_KEY.RECOVERY_KEY)
.getVisibleText()
.then((key) => {
recoveryKey = key;
})
);
});
registerSuite('post_verify_account_recovery', {
beforeEach: function () {
email = createEmail();
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'create account recovery': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
ACCOUNT_RECOVERY_URL,
selectors.POST_VERIFY_ADD_RECOVERY_KEY.HEADER
)
)
.then(
click(
selectors.POST_VERIFY_ADD_RECOVERY_KEY.SUBMIT,
selectors.POST_VERIFY_CONFIRM_PASSWORD.HEADER
)
)
.then(testElementExists(selectors.POST_VERIFY_CONFIRM_PASSWORD.HEADER))
.then(type(selectors.POST_VERIFY_CONFIRM_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.POST_VERIFY_CONFIRM_PASSWORD.SUBMIT,
selectors.POST_VERIFY_SAVE_RECOVERY_KEY.HEADER
)
)
.then(testElementExists(selectors.POST_VERIFY_SAVE_RECOVERY_KEY.HEADER))
.then(
testElementTextNotEmpty(
selectors.POST_VERIFY_SAVE_RECOVERY_KEY.RECOVERY_KEY
)
)
.then(getRecoveryKey())
.then(() => {
return this.remote
.then(
click(
selectors.POST_VERIFY_SAVE_RECOVERY_KEY.DONE,
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.HEADER
)
)
.then(
testElementExists(
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.HEADER
)
)
.then(
type(
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.RECOVERY_KEY,
'INVALIDKEY'
)
)
.then(
click(
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.SUBMIT,
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.TOOLTIP
)
)
.then(
visibleByQSA(selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.TOOLTIP)
)
.then(
testElementTextInclude(
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.TOOLTIP,
'Invalid account recovery key'
)
)
.then(
type(
selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.RECOVERY_KEY,
recoveryKey
)
)
.then(click(selectors.POST_VERIFY_CONFIRM_RECOVERY_KEY.SUBMIT))
.then(
testElementExists(
selectors.POST_VERIFY_RECOVERY_KEY_VERIFIED.HEADER
)
)
.then(click(selectors.POST_VERIFY_RECOVERY_KEY_VERIFIED.SUBMIT))
.then(testSuccessWasShown('Account recovery enabled'));
});
},
'abort account recovery at add_recovery_key': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
ACCOUNT_RECOVERY_URL,
selectors.POST_VERIFY_ADD_RECOVERY_KEY.HEADER
)
)
.then(click(selectors.POST_VERIFY_ADD_RECOVERY_KEY.MAYBE_LATER))
.then(testSuccessWasNotShown());
},
'abort account recovery at confirm_password': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
ACCOUNT_RECOVERY_URL,
selectors.POST_VERIFY_ADD_RECOVERY_KEY.HEADER
)
)
.then(click(selectors.POST_VERIFY_ADD_RECOVERY_KEY.SUBMIT))
.then(click(selectors.POST_VERIFY_CONFIRM_PASSWORD.MAYBE_LATER))
.then(testSuccessWasNotShown());
},
},
});

Просмотреть файл

@ -1,96 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const { assert } = intern.getPlugin('chai');
const FunctionalHelpers = require('./../lib/helpers');
const selectors = require('./../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync`;
const CAD_QR_URL = `${config.fxaContentRoot}post_verify/cad_qr/get_started?context=fx_desktop_v3&service=sync`;
const PASSWORD = 'password1234567';
const TEST_DEVICE_NAME = 'Test Runner Session Device';
const TEST_DEVICE_TYPE = 'mobile';
let email, accountData, client;
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
testElementExists,
} = FunctionalHelpers;
registerSuite('cad_qr', {
beforeEach: function () {
email = createEmail();
client = FunctionalHelpers.getFxaClient();
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then((result) => {
accountData = result;
});
},
tests: {
'CAD via QR code': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(
openPage(
CAD_QR_URL,
selectors.POST_VERIFY_CAD_QR_GET_STARTED.HEADER
)
)
.then(click(selectors.POST_VERIFY_CAD_QR_GET_STARTED.LATER))
.getCurrentUrl()
.then(function (url) {
assert.isTrue(url.includes('mozilla.org'));
})
.goBack()
.then(click(selectors.POST_VERIFY_CAD_QR_GET_STARTED.SUBMIT))
.then(click(selectors.POST_VERIFY_CAD_QR_READY_TO_SCAN.LATER))
.getCurrentUrl()
.then(function (url) {
assert.isTrue(url.includes('mozilla.org'));
})
.goBack()
.then(
testElementExists(selectors.POST_VERIFY_CAD_QR_READY_TO_SCAN.HEADER)
)
.then(click(selectors.POST_VERIFY_CAD_QR_READY_TO_SCAN.SUBMIT))
.then(
testElementExists(selectors.POST_VERIFY_CAD_QR_SCAN_CODE.HEADER)
)
// This page will be polling for a new device record. This typically
// happens when the user successfully authenticates on a new
// device.
.then(function () {
return client.deviceRegister(
accountData.sessionToken,
TEST_DEVICE_NAME,
TEST_DEVICE_TYPE
);
})
.then(
testElementExists(selectors.POST_VERIFY_CAD_QR_CONNECTED.HEADER)
)
);
},
},
});

Просмотреть файл

@ -1,108 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const { assert } = intern.getPlugin('chai');
const FunctionalHelpers = require('./../lib/helpers');
const selectors = require('./../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const ForceChangePassword =
config.fxaContentRoot + 'post_verify/password/force_password_change';
const ENTER_EMAIL_SYNC_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync`;
const OAUTH_APP = config.fxaOAuthApp;
const PASSWORD = 'password1234567';
const NEW_PASSWORD = '1234zxcvasdf';
let email;
const {
clearBrowserState,
createEmail,
createUser,
fillOutEmailFirstSignIn,
fillOutForceChangePassword,
fillOutSignInTokenCode,
openFxaFromRp,
openPage,
testElementExists,
testIsBrowserNotified,
thenify,
} = FunctionalHelpers;
const testAtOAuthApp = thenify(function () {
return this.parent
.then(testElementExists(selectors['123DONE'].AUTHENTICATED))
.getCurrentUrl()
.then(function (url) {
// redirected back to the App
assert.ok(url.indexOf(OAUTH_APP) > -1);
});
});
registerSuite('post_verify_force_password_change', {
beforeEach: function () {
email = createEmail('forcepwdchange{id}');
return this.remote
.then(clearBrowserState({ forceAll: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'navigate to page directly and can change password': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(fillOutSignInTokenCode(email, 0))
.then(
testElementExists(selectors.POST_VERIFY_FORCE_PASSWORD_CHANGE.HEADER)
)
.then(
openPage(
ForceChangePassword,
selectors.POST_VERIFY_FORCE_PASSWORD_CHANGE.HEADER
)
)
.then(fillOutForceChangePassword(PASSWORD, NEW_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'force change password on login - sync': function () {
return this.remote
.then(openPage(ENTER_EMAIL_SYNC_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(fillOutSignInTokenCode(email, 0))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(
testElementExists(selectors.POST_VERIFY_FORCE_PASSWORD_CHANGE.HEADER)
)
.then(fillOutForceChangePassword(PASSWORD, NEW_PASSWORD))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER));
},
'force change password on login - oauth': function () {
return this.remote
.then(openFxaFromRp('enter-email'))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(fillOutSignInTokenCode(email, 0))
.then(
testElementExists(selectors.POST_VERIFY_FORCE_PASSWORD_CHANGE.HEADER)
)
.then(fillOutForceChangePassword(PASSWORD, NEW_PASSWORD))
.then(testAtOAuthApp());
},
},
});

Просмотреть файл

@ -1,77 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./../lib/helpers');
const selectors = require('./../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const Newsletters =
config.fxaContentRoot + 'post_verify/newsletters/add_newsletters';
const PASSWORD = 'password1234567';
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
testElementExists,
testElementTextInclude,
} = FunctionalHelpers;
registerSuite('post_verify_newsletters', {
beforeEach: function () {
email = createEmail();
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'subscribe to newsletters': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(Newsletters, selectors.POST_VERIFY_ADD_NEWSLETTERS.HEADER, {})
)
.then(
click(selectors.POST_VERIFY_ADD_NEWSLETTERS.NEWSLETTERS.ONLINE_SAFETY)
)
.then(
click(
selectors.POST_VERIFY_ADD_NEWSLETTERS.NEWSLETTERS.HEALTHY_INTERNET
)
)
.then(
testElementTextInclude(
selectors.POST_VERIFY_ADD_NEWSLETTERS.SUBMIT,
email
)
)
.then(
testElementTextInclude(
selectors.POST_VERIFY_ADD_NEWSLETTERS.DESCRIPTION,
'Get practical knowledge in your inbox'
)
)
.then(click(selectors.POST_VERIFY_ADD_NEWSLETTERS.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
},
});

Просмотреть файл

@ -1,98 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./../lib/helpers');
const selectors = require('./../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const ENTER_SECONDARY_EMAIL =
config.fxaContentRoot + 'post_verify/secondary_email/add_secondary_email';
const PASSWORD = 'password1234567';
let email, secondaryEmail;
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutPostVerifySecondaryEmailCode,
fillOutEmailFirstSignIn,
openPage,
testElementExists,
type,
} = FunctionalHelpers;
registerSuite('post_verify_secondary_email', {
beforeEach: function () {
email = createEmail();
secondaryEmail = createEmail();
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'create secondary email': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
ENTER_SECONDARY_EMAIL,
selectors.POST_VERIFY_ADD_SECONDARY_EMAIL.HEADER
)
)
.then(
type(
selectors.POST_VERIFY_ADD_SECONDARY_EMAIL.EMAIL,
secondaryEmail
)
)
.then(click(selectors.POST_VERIFY_ADD_SECONDARY_EMAIL.SUBMIT))
.then(
testElementExists(
selectors.POST_VERIFY_CONFIRM_SECONDARY_EMAIL.HEADER
)
)
// Click `use different email` and verify you can
.then(
click(
selectors.POST_VERIFY_CONFIRM_SECONDARY_EMAIL.USE_DIFFERENT_EMAIL
)
)
.then(
testElementExists(selectors.POST_VERIFY_ADD_SECONDARY_EMAIL.HEADER)
)
.then(
type(
selectors.POST_VERIFY_ADD_SECONDARY_EMAIL.EMAIL,
secondaryEmail
)
)
.then(click(selectors.POST_VERIFY_ADD_SECONDARY_EMAIL.SUBMIT))
// Complete the email verification flow
.then(fillOutPostVerifySecondaryEmailCode(secondaryEmail, 1))
.then(testElementExists(selectors.POST_VERIFY_VERIFIED.READY))
.then(click(selectors.POST_VERIFY_VERIFIED.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
},
});

Просмотреть файл

@ -1,49 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const ENTER_EMAIL_URL = intern._config.fxaContentRoot;
const {
clearBrowserState,
click,
createEmail,
openPage,
type,
} = FunctionalHelpers;
registerSuite('privacy policy', {
beforeEach: function () {
return this.remote.then(clearBrowserState());
},
tests: {
'from signup': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, createEmail()))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
)
.then(
click(
selectors.SIGNUP_PASSWORD.PRIVACY_POLICY,
selectors.PRIVACY_POLICY.HEADER
)
)
.then(
click(
selectors.PRIVACY_POLICY.LINK_BACK,
selectors.SIGNUP_PASSWORD.HEADER
)
);
},
},
});

Просмотреть файл

@ -1,71 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const QUERY_PARAMS = '?context=fx_desktop_v3&service=sync&action=email';
const ENTER_EMAIL_URL = `${config.fxaContentRoot}${QUERY_PARAMS}`;
const PASSWORD = 'password1234567';
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
testElementExists,
} = FunctionalHelpers;
registerSuite('push_login', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'verify login via push - treatment': function () {
return this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceExperiment: 'pushLogin',
forceExperimentGroup: 'treatment',
},
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.PUSH_VERIFY_LOGIN.HEADER))
.then(click(selectors.PUSH_VERIFY_LOGIN.RESEND))
.then(click(selectors.PUSH_VERIFY_LOGIN.SEND_EMAIL))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER));
},
control: function () {
return this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceExperiment: 'pushLogin',
forceExperimentGroup: 'control',
},
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER));
},
},
});

Просмотреть файл

@ -1,43 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
var AUTOMATED = '?automatedBrowser=true';
var ENTER_EMAIL_URL = intern._config.fxaContentRoot + AUTOMATED;
var clearBrowserState = FunctionalHelpers.clearBrowserState;
var openPage = FunctionalHelpers.openPage;
var testAreEventsLogged = FunctionalHelpers.testAreEventsLogged;
var testElementExists = FunctionalHelpers.testElementExists;
registerSuite('refreshing a screen logs a refresh event', {
beforeEach: function () {
return this.remote.then(clearBrowserState());
},
tests: {
'refreshing the enter_email screen': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.refresh()
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// Unload the page to flush the metrics
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(
testAreEventsLogged([
'screen.enter-email',
'screen.enter-email',
'signup.refresh',
])
)
);
},
},
});

Просмотреть файл

@ -1,629 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const ENTER_EMAIL_PAGE_URL = config.fxaContentRoot;
const RESET_PAGE_URL = config.fxaContentRoot + 'reset_password';
const CONFIRM_PAGE_URL = config.fxaContentRoot + 'confirm_reset_password';
const COMPLETE_PAGE_URL_ROOT =
config.fxaContentRoot + 'complete_reset_password';
const PASSWORD = 'passwordzxcv';
const TIMEOUT = 90 * 1000;
let client;
let code;
let email;
let token;
const {
clearBrowserState,
click,
closeCurrentWindow,
createEmail,
createRandomHexString,
createUser,
fillOutCompleteResetPassword,
fillOutResetPassword,
getFxaClient,
getVerificationLink,
noSuchElement,
openExternalSite,
openPage,
openPasswordResetLinkInDifferentBrowser,
openVerificationLinkInNewTab,
openVerificationLinkInSameTab,
switchToWindow,
testElementExists,
testElementValueEquals,
testEmailExpected,
testSuccessWasShown,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
/**
* Programatically initiate a reset password using the
* FxA Client. Saves the token and code.
*/
const initiateResetPassword = thenify(function (emailAddress, emailNumber) {
return this.parent
.then(() => client.passwordForgotSendCode(emailAddress))
.then(getVerificationLink(emailAddress, emailNumber))
.then((link) => {
// token and code are hex values
token = link.match(/token=([a-f\d]+)/)[1];
code = link.match(/code=([a-f\d]+)/)[1];
});
});
const openCompleteResetPassword = thenify(function (
email,
token,
code,
header
) {
let url = COMPLETE_PAGE_URL_ROOT + '?';
const queryParams = [];
if (email) {
queryParams.push('email=' + encodeURIComponent(email));
}
if (token) {
queryParams.push('token=' + encodeURIComponent(token));
}
if (code) {
queryParams.push('code=' + encodeURIComponent(code));
}
url += queryParams.join('&');
return this.parent.then(openPage(url, header));
});
const testAtSettingsWithVerifiedMessage = thenify(function () {
return this.parent
.setFindTimeout(intern._config.pageLoadTimeout)
.sleep(1000)
.then(testElementExists(selectors.SETTINGS.HEADER));
// TODO: https://github.com/mozilla/fxa/issues/7882
// .then(testSuccessWasShown());
});
const testAtSettings = thenify(function () {
return this.parent
.setFindTimeout(intern._config.pageLoadTimeout)
.sleep(1000)
.then(testElementExists(selectors.SETTINGS.HEADER));
});
registerSuite('reset_password', {
beforeEach: function () {
this.timeout = TIMEOUT;
email = createEmail();
return this.remote
.then(() => getFxaClient())
.then((_client) => {
client = _client;
})
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState());
},
tests: {
'visit confirmation screen without initiating reset_password, user is redirected to /reset_password': function () {
// user is immediately redirected to /reset_password if they have no
// sessionToken.
// Success is showing the screen
return (
this.remote
.then(openPage(CONFIRM_PAGE_URL, selectors.RESET_PASSWORD.HEADER))
// There was an error were users who browsed directly to /confirm_reset_password were
// displayed the 400 page. The user should not see the error but should be allowed
// to fill out their email address. See #6724
.then(noSuchElement(selectors['400'].HEADER, 5000))
);
},
'open /reset_password page from /signin': function () {
const updatedEmail = createEmail();
return (
this.remote
.then(openPage(ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(click(selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
// email should not be pre-filled
.then(testElementValueEquals(selectors.RESET_PASSWORD.EMAIL, ''))
// go back, ensure the email address is still pre-filled on the signin page.
.then(click(selectors.RESET_PASSWORD.LINK_SIGNIN))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(click(selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD))
// update the email in the reset_password form, go back, ensure the
// change is reflected in the /signin page
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
.then(testElementValueEquals(selectors.RESET_PASSWORD.EMAIL, ''))
.then(type(selectors.RESET_PASSWORD.EMAIL, updatedEmail))
.then(click(selectors.RESET_PASSWORD.LINK_SIGNIN))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(
testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, updatedEmail)
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(click(selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
.then(testElementValueEquals(selectors.RESET_PASSWORD.EMAIL, ''))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
//Check email resent for reset password
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_RESEND))
//Confirm the success message for resend email
.then(visibleByQSA(selectors.CONFIRM_RESET_PASSWORD.RESEND_SUCCESS))
//continue to sign in again
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_SIGNIN))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
);
},
'enter an email with leading whitespace': function () {
return this.remote
.then(fillOutResetPassword(' ' + email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER));
},
'enter an email with trailing whitespace': function () {
return this.remote
.then(fillOutResetPassword(email + ' '))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER));
},
'open confirm_reset_password page, click resend': function () {
return (
this.remote
.then(fillOutResetPassword(email))
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_RESEND))
.then(testEmailExpected(email, 1))
// Success is showing the success message
.then(
testSuccessWasShown(
'Email resent. Add accounts@firefox.com to your contacts to ensure a smooth delivery.',
'.success[data-shown]'
)
)
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_RESEND))
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_RESEND))
// Stills shows success message
//
// this uses .visibleByQSA instead of testSuccessWasShown because
// the element is not re-shown, but rather should continue to
// be visible.
.then(visibleByQSA(selectors.CONFIRM_RESET_PASSWORD.RESEND_SUCCESS))
);
},
'open complete page with missing token shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(
openCompleteResetPassword(
email,
null,
code,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
)
);
},
'open complete page with malformed token shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(function () {
const malformedToken = createRandomHexString(token.length - 1);
return openCompleteResetPassword(
email,
malformedToken,
code,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
).call(this);
});
},
'open complete page with invalid token shows expired screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(function () {
const invalidToken = createRandomHexString(token.length);
return openCompleteResetPassword(
email,
invalidToken,
code,
selectors.COMPLETE_RESET_PASSWORD.EXPIRED_LINK_HEADER
).call(this);
});
},
'open complete page with empty token shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(
openCompleteResetPassword(
email,
'',
code,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
)
);
},
'open complete page with missing code shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(
openCompleteResetPassword(
email,
token,
null,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
)
);
},
'open complete page with empty code shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(
openCompleteResetPassword(
email,
token,
'',
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
)
);
},
'open complete page with malformed code shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(function () {
const malformedCode = createRandomHexString(code.length - 1);
return openCompleteResetPassword(
email,
token,
malformedCode,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
).call(this);
});
},
'open complete page with missing email shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(
openCompleteResetPassword(
null,
token,
code,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
)
);
},
'open complete page with empty email shows damaged screen': function () {
return this.remote
.then(initiateResetPassword(email, 0))
.then(
openCompleteResetPassword(
'',
token,
code,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER
)
);
},
'open complete page with malformed email shows damaged screen': function () {
return this.remote.then(initiateResetPassword(email, 0)).then(
openCompleteResetPassword(
'invalidemail',
token,
code,
selectors.COMPLETE_RESET_PASSWORD.DAMAGED_LINK_HEADER // #fxa-reset-link-damaged-header
)
);
},
'reset password, verify same browser': function () {
this.timeout = TIMEOUT;
return (
this.remote
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInNewTab(email, 0))
// Complete the reset password in the new tab
.then(switchToWindow(1))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
// this tab's success is seeing the reset password complete header.
.then(testAtSettingsWithVerifiedMessage())
.then(closeCurrentWindow())
.then(testAtSettings())
);
},
'reset password, verify same browser with original tab closed': function () {
return (
this.remote
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
// user browses to another site.
.then(openExternalSite())
.then(openVerificationLinkInNewTab(email, 0))
.then(switchToWindow(1))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
// this tab's success is seeing the reset password complete header.
.then(testAtSettingsWithVerifiedMessage())
// switch to the original window
.then(closeCurrentWindow())
);
},
'reset password, verify same browser by replacing the original tab': function () {
this.timeout = 90 * 1000;
return (
this.remote
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 0))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
// this tab's success is seeing the reset password complete header.
.then(testAtSettingsWithVerifiedMessage())
);
},
"reset password, verify in a different browser, from the original tab's P.O.V.": function () {
this.timeout = 90 * 1000;
return (
this.remote
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openPasswordResetLinkInDifferentBrowser(email, PASSWORD))
// user verified in a new browser, they have to enter
// their updated credentials in the original tab.
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(
testSuccessWasShown(
'Password reset successfully. Sign in to continue.',
'.success[data-shown]'
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
// no success message, the user should have seen that above.
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
"reset password, verify in a different browser, from the new browser's P.O.V.": function () {
this.timeout = 90 * 1000;
return (
this.remote
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
// clear all browser state, simulate opening in
// a new browser
.then(clearBrowserState({ contentServer: true }))
.then(openVerificationLinkInSameTab(email, 0))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testAtSettingsWithVerifiedMessage())
);
},
},
});
registerSuite('try to re-use a link', {
beforeEach: function () {
this.timeout = TIMEOUT;
email = createEmail();
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(initiateResetPassword(email, 0))
.then(clearBrowserState());
},
tests: {
'complete reset, then re-open verification link, click resend': function () {
this.timeout = TIMEOUT;
return this.remote
.then(
openCompleteResetPassword(
email,
token,
code,
selectors.COMPLETE_RESET_PASSWORD.HEADER
)
)
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openCompleteResetPassword(
email,
token,
code,
selectors.COMPLETE_RESET_PASSWORD.EXPIRED_LINK_HEADER
)
)
.then(click(selectors.CONFIRM_RESET_PASSWORD.LINK_RESEND))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER));
},
},
});
registerSuite('reset_password with email specified on URL', {
beforeEach: function () {
email = createEmail();
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState());
},
tests: {
'browse directly to page with email on query params': function () {
const url = RESET_PAGE_URL + '?email=' + email;
return (
this.remote
.then(openPage(url, selectors.RESET_PASSWORD.HEADER))
// email address should not be pre-filled from the query param.
.then(testElementValueEquals(selectors.RESET_PASSWORD.EMAIL, ''))
// ensure there is no back button when browsing directly to page
.then(noSuchElement(selectors.RESET_PASSWORD.BACK))
// fill in email
.then(type(selectors.RESET_PASSWORD.EMAIL, email))
.then(click(selectors.RESET_PASSWORD.SUBMIT))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
);
},
},
});
registerSuite('password change while at confirm_reset_password screen', {
beforeEach: function () {
email = createEmail();
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(() => getFxaClient())
.then((_client) => {
client = _client;
})
.then(clearBrowserState());
},
tests: {
'original page transitions after completion': function () {
return this.remote
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(function () {
return client.signIn(email, PASSWORD);
})
.then(function (accountInfo) {
return client.passwordChange(email, PASSWORD, 'newpassword', {
sessionToken: accountInfo.sessionToken,
});
})
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER));
},
},
});
registerSuite('reset_password with unknown email', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState());
},
tests: {
'open /reset_password page, enter unknown email, wait for error': function () {
return (
this.remote
.then(fillOutResetPassword(email))
// The error area shows a link to /signup
.then(visibleByQSA(selectors.RESET_PASSWORD.ERROR))
.then(click(selectors.RESET_PASSWORD.LINK_ERROR_SIGNUP))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// check the email address was written
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
);
},
},
});

Просмотреть файл

@ -1,202 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const config = intern._config;
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutCompleteResetPassword,
fillOutEmailFirstSignIn,
getFxaClient,
getVerificationLink,
noSuchElement,
openPage,
testElementExists,
testElementTextInclude,
thenify,
} = FunctionalHelpers;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const SECURITY_EVENTS_URL = `${config.fxaContentRoot}security_events`;
const COMPLETE_PAGE_URL_ROOT =
config.fxaContentRoot + 'complete_reset_password';
const PASSWORD = 'passwordzxcv';
let client;
let code;
let email;
let token;
const initiateResetPassword = thenify(function (emailAddress, emailNumber) {
client = getFxaClient();
return this.parent
.then(() => client.passwordForgotSendCode(emailAddress))
.then(getVerificationLink(emailAddress, emailNumber))
.then((link) => {
// token and code are hex values
token = link.match(/token=([a-f\d]+)/)[1];
code = link.match(/code=([a-f\d]+)/)[1];
});
});
const openCompleteResetPassword = thenify(function (
email,
token,
code,
header
) {
let url = COMPLETE_PAGE_URL_ROOT + '?';
const queryParams = [];
if (email) {
queryParams.push('email=' + encodeURIComponent(email));
}
if (token) {
queryParams.push('token=' + encodeURIComponent(token));
}
if (code) {
queryParams.push('code=' + encodeURIComponent(code));
}
url += queryParams.join('&');
return this.parent.then(openPage(url, header));
});
registerSuite('security_events', {
beforeEach: function () {
email = createEmail();
return this.remote
.then(clearBrowserState({ forceAll: true }))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(initiateResetPassword(email, 0));
},
tests: {
'gets security events table': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD, true))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
SECURITY_EVENTS_URL,
selectors.SECURITY_EVENTS.RECENT_ACTIVITY_HEADER
)
)
.then(
testElementExists(selectors.SECURITY_EVENTS.SECURITY_EVENTS_HEADER)
);
},
'login event is shown': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD, true))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
SECURITY_EVENTS_URL,
selectors.SECURITY_EVENTS.RECENT_ACTIVITY_HEADER
)
)
.then(
testElementTextInclude(
selectors.SECURITY_EVENTS.FIRST_EVENT_NAME,
'account.login'
)
);
},
'reset event is shown': function () {
return this.remote
.then(
openCompleteResetPassword(
email,
token,
code,
selectors.COMPLETE_RESET_PASSWORD.HEADER
)
)
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openCompleteResetPassword(
email,
token,
code,
selectors.COMPLETE_RESET_PASSWORD.EXPIRED_LINK_HEADER
)
)
.then(
click(
selectors.CONFIRM_RESET_PASSWORD.LINK_RESEND,
selectors.CONFIRM_RESET_PASSWORD.HEADER
)
)
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(
openPage(
SECURITY_EVENTS_URL,
selectors.SECURITY_EVENTS.RECENT_ACTIVITY_HEADER
)
)
.then(
testElementTextInclude(
selectors.SECURITY_EVENTS.EVENT_TABLE,
'account.reset'
)
);
},
'delete security events': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD, true))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
openPage(
SECURITY_EVENTS_URL,
selectors.SECURITY_EVENTS.RECENT_ACTIVITY_HEADER
)
)
.then(
testElementTextInclude(
selectors.SECURITY_EVENTS.FIRST_EVENT_NAME,
'account.login'
)
)
.then(
testElementExists(selectors.SECURITY_EVENTS.DELETE_EVENTS_BUTTON)
)
.then(click(selectors.SECURITY_EVENTS.DELETE_EVENTS_BUTTON))
// reload the page to verify that all the security events have been deleted
.refresh()
.then(noSuchElement(selectors.SECURITY_EVENTS.SECURITY_EVENT))
);
},
},
});

Просмотреть файл

@ -1,285 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('../lib/helpers');
const selectors = require('../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const PASSWORD = 'passwordzxcv';
const NEW_PASSWORD = 'passwordzxcv1';
let email;
let secondaryEmail;
let newPrimaryEmail;
const {
addAndVerifySecondaryEmail,
clearBrowserState,
click,
createEmail,
fillOutDeleteAccount,
fillOutChangePassword,
fillOutEmailFirstSignUp,
fillOutEmailFirstSignIn,
fillOutSignInUnblock,
fillOutSignUpCode,
openPage,
signOut,
testElementExists,
testElementTextEquals,
testElementTextInclude,
testErrorTextInclude,
testSuccessWasShown,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('settings change email', {
beforeEach: function () {
email = createEmail();
secondaryEmail = createEmail();
return (
this.remote
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(visibleByQSA(selectors.SETTINGS.PROFILE_HEADER))
.then(click(selectors.EMAIL.MENU_BUTTON))
.then(addAndVerifySecondaryEmail(secondaryEmail))
.then(testSuccessWasShown())
// set new primary email
.then(
click(
selectors.SETTINGS.SECONDARY_EMAIL.MAKE_PRIMARY,
selectors.EMAIL.SUCCESS
)
)
.then(visibleByQSA(selectors.EMAIL.SUCCESS))
.then(
testElementTextEquals(selectors.EMAIL.ADDRESS_LABEL, secondaryEmail)
)
);
},
tests: {
'can change primary email and login': function () {
return (
this.remote
.then(signOut())
// sign in with old primary email fails
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testErrorTextInclude('Primary account email required'))
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
// sign in with new primary email
.then(fillOutEmailFirstSignIn(secondaryEmail, PASSWORD))
// shows new primary email
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
testElementTextEquals(
selectors.SETTINGS.PROFILE_HEADER,
secondaryEmail
)
)
);
},
'can change primary email, change password and login': function () {
return (
this.remote
// change password
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(fillOutChangePassword(PASSWORD, NEW_PASSWORD))
// sign out and fails login with old password
.then(signOut())
.then(fillOutEmailFirstSignIn(secondaryEmail, PASSWORD))
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.TOOLTIP))
// sign in with new password
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, NEW_PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(
testElementTextEquals(
selectors.SETTINGS.PROFILE_HEADER,
secondaryEmail
)
)
);
},
'can change primary email, change password, login, change email and login': function () {
return (
this.remote
// change password
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(fillOutChangePassword(PASSWORD, NEW_PASSWORD))
// sign out and fails login with old password
.then(signOut())
.then(fillOutEmailFirstSignIn(secondaryEmail, PASSWORD))
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.TOOLTIP))
// sign in with new password
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(secondaryEmail, NEW_PASSWORD))
.then(
testElementTextEquals(
selectors.SETTINGS.PROFILE_HEADER,
secondaryEmail
)
)
// set primary email to original email
.then(
testElementTextEquals(
selectors.SETTINGS.SECONDARY_EMAIL.HEADER_VALUE,
email
)
)
.then(click(selectors.EMAIL.SET_PRIMARY_EMAIL_BUTTON))
.then(visibleByQSA(selectors.EMAIL.SUCCESS))
// sign out and login with new password
.then(signOut())
.then(fillOutEmailFirstSignIn(email, NEW_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'can change primary email, delete account': function () {
return (
this.remote
// go to delete account screen
.then(
click(
selectors.SETTINGS_DELETE_ACCOUNT.DELETE_ACCOUNT_BUTTON,
selectors.SETTINGS_DELETE_ACCOUNT.DETAILS
)
)
// enter correct password for deleting account
.then(fillOutDeleteAccount(PASSWORD))
// Try creating a new account with the same secondary email as previous account and new password
.then(fillOutEmailFirstSignUp(secondaryEmail, NEW_PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(secondaryEmail, 3))
.then(testElementExists(selectors.SETTINGS.HEADER))
// Verify that user can add the same primary email as secondary as used in the previous account
.then(click(selectors.EMAIL.MENU_BUTTON))
.then(addAndVerifySecondaryEmail(email, 3))
.then(testSuccessWasShown())
);
},
},
});
registerSuite('settings change email - unblock', {
beforeEach: function () {
email = createEmail();
// Create a new primary email that is always forced through the unblock flow
newPrimaryEmail = createEmail('blocked{id}');
return (
this.remote
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(click(selectors.EMAIL.MENU_BUTTON))
.then(addAndVerifySecondaryEmail(newPrimaryEmail))
.then(testSuccessWasShown())
// set new primary email
.then(
click(
selectors.SETTINGS.SECONDARY_EMAIL.MAKE_PRIMARY,
selectors.EMAIL.SUCCESS
)
)
.then(visibleByQSA(selectors.EMAIL.SUCCESS))
.then(
testElementTextEquals(selectors.EMAIL.ADDRESS_LABEL, newPrimaryEmail)
)
// sign out
.then(signOut())
);
},
afterEach: function () {
return this.remote.then(clearBrowserState());
},
tests: {
'can change primary email, get blocked with invalid password, redirect enter password page': function () {
return (
this.remote
// sign in
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(newPrimaryEmail, 'INVALID_PASSWORD'))
// fill out unblock
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(
selectors.SIGNIN_UNBLOCK.VERIFICATION,
newPrimaryEmail
)
)
.then(fillOutSignInUnblock(newPrimaryEmail, 3))
// redirected to correct password
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
);
},
'can change primary email, get blocked with valid password, redirect settings page': function () {
return (
this.remote
// sign in
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(newPrimaryEmail, PASSWORD))
// fill out unblock
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(
selectors.SIGNIN_UNBLOCK.VERIFICATION,
newPrimaryEmail
)
)
.then(fillOutSignInUnblock(newPrimaryEmail, 3))
// redirected to settings
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
},
});

Просмотреть файл

@ -1,247 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('../lib/helpers');
const selectors = require('../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const ANIMATION_DELAY_MS = 500;
const FIRST_PASSWORD = 'password';
const SECOND_PASSWORD = 'new_password';
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
denormalizeStoredEmail,
fillOutChangePassword,
fillOutEmailFirstSignIn,
noSuchElement,
openPage,
pollUntilHiddenByQSA,
testElementExists,
testElementTextEquals,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
const setupTest = thenify(function (options = {}) {
const signUpEmail = options.signUpEmail || email;
const signInEmail = options.signInEmail || email;
return this.parent
.then(createUser(signUpEmail, FIRST_PASSWORD, { preVerified: true }))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(signInEmail, FIRST_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(
testElementTextEquals(selectors.SETTINGS.PROFILE_HEADER, signUpEmail)
);
});
registerSuite('change password', {
beforeEach: function () {
email = createEmail();
},
tests: {
'try to change password with an incorrect old password': function () {
return (
this.remote
.then(setupTest())
// Go to change password screen
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(
fillOutChangePassword('INCORRECT', SECOND_PASSWORD, {
expectSuccess: false,
})
)
// the validation tooltip should be visible
.then(visibleByQSA(selectors.CHANGE_PASSWORD.TOOLTIP))
// Change form so that it is valid, error should be hidden.
.then(type(selectors.CHANGE_PASSWORD.OLD_PASSWORD, FIRST_PASSWORD))
.then(noSuchElement(selectors.CHANGE_PASSWORD.TOOLTIP))
);
},
'try to change password with short password, tooltip shows, cancel, try to change password again, tooltip is not shown': function () {
return (
this.remote
.then(setupTest())
// Go to change password screen
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(
fillOutChangePassword('A', SECOND_PASSWORD, {
expectSuccess: false,
})
)
// the validation tooltip should be visible
.then(visibleByQSA(selectors.CHANGE_PASSWORD.TOOLTIP))
// click the cancel button
.then(click(selectors.CHANGE_PASSWORD.CANCEL_BUTTON))
.sleep(ANIMATION_DELAY_MS)
// try to change password again
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
// check no tooltip exists
.then(noSuchElement(selectors.CHANGE_PASSWORD.TOOLTIP))
);
},
'new_password validation': function () {
return (
this.remote
.then(setupTest())
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
// new_password empty
.then(click(selectors.CHANGE_PASSWORD.OLD_PASSWORD_LABEL))
.then(type(selectors.CHANGE_PASSWORD.OLD_PASSWORD, FIRST_PASSWORD))
.then(
testElementExists(selectors.SETTINGS.CHANGE_PASSWORD.UNSET_LENGTH)
)
// new_password too short
.then(click(selectors.CHANGE_PASSWORD.NEW_PASSWORD_LABEL))
.then(type(selectors.CHANGE_PASSWORD.NEW_PASSWORD, 'pass'))
.then(
testElementExists(selectors.SETTINGS.CHANGE_PASSWORD.INVALID_LENGTH)
)
// new_password too close to the email address
.then(click(selectors.CHANGE_PASSWORD.NEW_PASSWORD_LABEL))
.then(type(selectors.CHANGE_PASSWORD.NEW_PASSWORD, email))
.then(
testElementExists(
selectors.SETTINGS.CHANGE_PASSWORD.INVALID_SIMILAR_TO_EMAIL
)
)
// new_password too common
.then(click(selectors.CHANGE_PASSWORD.NEW_PASSWORD_LABEL))
.then(type(selectors.CHANGE_PASSWORD.NEW_PASSWORD, 'password'))
.then(
testElementExists(
selectors.SETTINGS.CHANGE_PASSWORD.INVALID_TOO_COMMON
)
)
// all good
.then(click(selectors.CHANGE_PASSWORD.NEW_PASSWORD_LABEL))
.then(type(selectors.CHANGE_PASSWORD.NEW_PASSWORD, SECOND_PASSWORD))
.then(click(selectors.CHANGE_PASSWORD.NEW_VPASSWORD_LABEL))
.then(type(selectors.CHANGE_PASSWORD.NEW_VPASSWORD, SECOND_PASSWORD))
.then(
testElementExists(selectors.SETTINGS.CHANGE_PASSWORD.VALID_LENGTH)
)
.then(
testElementExists(
selectors.SETTINGS.CHANGE_PASSWORD.VALID_SIMILAR_TO_EMAIL
)
)
.then(
testElementExists(
selectors.SETTINGS.CHANGE_PASSWORD.VALID_TOO_COMMON
)
)
.then(
testElementExists(
selectors.SETTINGS.CHANGE_PASSWORD.VALID_PASSWORD_MATCH
)
)
.then(click(selectors.CHANGE_PASSWORD.SUBMIT))
.then(pollUntilHiddenByQSA(selectors.CHANGE_PASSWORD.DETAILS))
);
},
'change password, sign in with new password': function () {
return (
this.remote
.then(setupTest())
// Go to change password screen
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(fillOutChangePassword(FIRST_PASSWORD, SECOND_PASSWORD))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, SECOND_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'sign in with an unnormalized email, change password, sign in with new password': function () {
return (
this.remote
.then(
setupTest({ signInEmail: email.toUpperCase(), signUpEmail: email })
)
// Go to change password screen
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(fillOutChangePassword(FIRST_PASSWORD, SECOND_PASSWORD))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, SECOND_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'cached unnormalized email, change password, sign in with new password': function () {
return (
this.remote
.then(setupTest())
// synthesize a user who signed in pre #4470 with an unnormalized email
.then(denormalizeStoredEmail(email))
// refresh to load denormalized email from localStorage
.refresh()
// email should be normalized on refresh!
.then(testElementTextEquals(selectors.SETTINGS.PROFILE_HEADER, email))
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(fillOutChangePassword(FIRST_PASSWORD, SECOND_PASSWORD))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, SECOND_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'reset password via settings works': function () {
return (
this.remote
.then(setupTest())
// Go to change password screen
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(click(selectors.CHANGE_PASSWORD.LINK_RESET_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
);
},
},
});

Просмотреть файл

@ -1,110 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const intern = require('intern').default;
const config = intern._config;
const { describe, it, beforeEach } = intern.getPlugin('interface.bdd');
const selectors = require('../lib/selectors');
const FunctionalHelpers = require('../lib/helpers');
const { createEmail } = FunctionalHelpers;
const connectedServices = selectors.SETTINGS.CONNECTED_SERVICES;
describe('connected services: oauth clients', () => {
let email;
const password = 'topnotchsupercoolpassworddealwithit';
let {
clearBrowserState,
openFxaFromRp,
fillOutEmailFirstSignUp,
testElementExists,
fillOutSignUpCode,
openPage,
testElementTextInclude,
click,
pollUntilGoneByQSA,
noSuchElement,
openTab,
switchToWindow,
closeCurrentWindow,
} = FunctionalHelpers;
beforeEach(async ({ remote }) => {
({
clearBrowserState,
openFxaFromRp,
fillOutEmailFirstSignUp,
testElementExists,
fillOutSignUpCode,
openPage,
testElementTextInclude,
click,
pollUntilGoneByQSA,
noSuchElement,
openTab,
switchToWindow,
closeCurrentWindow,
} = FunctionalHelpers.applyRemote(remote));
await clearBrowserState({
forceAll: true,
});
});
it('lists and disconnects RP clients', async (remote) => {
email = createEmail();
await openFxaFromRp('enter-email');
await fillOutEmailFirstSignUp(email, password);
await testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER);
await fillOutSignUpCode(email, 0);
await testElementExists(selectors['123DONE'].AUTHENTICATED);
// client is listed
await openPage(config.fxaSettingsV2Root, connectedServices.HEADER);
await testElementTextInclude(connectedServices.HEADER, '123Done');
await openTab(config.fxaUntrustedOauthApp);
await switchToWindow(1);
await click(selectors['123DONE'].BUTTON_SIGNIN);
await click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN);
await testElementExists(selectors.OAUTH_PERMISSIONS.HEADER);
await click(selectors.OAUTH_PERMISSIONS.SUBMIT);
await testElementExists(selectors['123DONE'].AUTHENTICATED);
await closeCurrentWindow();
// refresh the list
await click(connectedServices.REFRESH_BUTTON);
await testElementTextInclude(connectedServices.HEADER, '321Done');
// disconnect
await click(
`${connectedServices.SERVICE}[data-name^="123"] ${connectedServices.SIGN_OUT}`
);
await pollUntilGoneByQSA(
`${connectedServices.SERVICE}[data-name^="123"] ${connectedServices.SIGN_OUT}`
);
// refresh to confirm app and its tokens are gone
await click(connectedServices.REFRESH_BUTTON);
await noSuchElement(
`${connectedServices.SERVICE}[data-name^="123"] ${connectedServices.SIGN_OUT}`
);
});
it('redirect from /settings/clients', async () => {
email = createEmail();
await openFxaFromRp('enter-email');
await fillOutEmailFirstSignUp(email, password);
await testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER);
await fillOutSignUpCode(email, 0);
await testElementExists(selectors['123DONE'].AUTHENTICATED);
const oldUrl = `${config.fxaSettingsV2Root}/clients`;
// page is redirected and client list is shown
await openPage(oldUrl, connectedServices.HEADER);
await testElementTextInclude(connectedServices.HEADER, '123Done');
});
});

Просмотреть файл

@ -1,155 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('../lib/helpers');
const selectors = require('../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const DELETE_ACCOUNT_URL = `${config.fxaContentRoot}settings/delete_account` ;
const PASSWORD = 'password1234567';
let email;
const {
clearBrowserState,
click,
createEmail,
createUser,
type,
fillOutEmailFirstSignIn,
testElementTextInclude,
openPage,
pollUntilHiddenByQSA,
visibleByQSA,
testElementExists,
} = FunctionalHelpers;
registerSuite('delete_account', {
beforeEach: function () {
email = createEmail();
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }));
},
tests: {
'sign in, delete account': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
// Go to delete account screen
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.DELETE_ACCOUNT_BUTTON))
.then(testElementExists(selectors.SETTINGS_DELETE_ACCOUNT.DETAILS))
// Intern won't click on checkboxes with SVGs on top. So click the
// checkbox labels instead :-\
.findAllByCssSelector(selectors.SETTINGS_DELETE_ACCOUNT.CHECKBOXES)
.then((labels) => labels.map((label) => label.click()))
.end()
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.SUBMIT_BUTTON))
// enter incorrect password
// but first, click the label to get it out of the way.
.then(
testElementExists(
selectors.SETTINGS.DELETE_ACCOUNT.INPUT_PASSWORD_LABEL
)
)
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.INPUT_PASSWORD_LABEL))
.then(
type(
selectors.SETTINGS_DELETE_ACCOUNT.INPUT_PASSWORD,
'incorrect password'
)
)
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.CONFIRM))
.then(
visibleByQSA(
selectors.SETTINGS_DELETE_ACCOUNT.TOOLTIP_INCORRECT_PASSWORD
)
)
//enter correct password
.then(
type(selectors.SETTINGS_DELETE_ACCOUNT.INPUT_PASSWORD, PASSWORD)
)
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.CONFIRM))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
);
},
'sign in, cancel delete account': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// Go to delete account screen
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.DELETE_ACCOUNT_BUTTON))
.then(testElementExists(selectors.SETTINGS_DELETE_ACCOUNT.DETAILS))
// Intern won't click on checkboxes with SVGs on top. So click the
// checkbox labels instead :-\
.findAllByCssSelector(selectors.SETTINGS_DELETE_ACCOUNT.CHECKBOXES)
.then((labels) => labels.map((label) => label.click()))
.end()
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.SUBMIT_BUTTON))
.then(
testElementExists(
selectors.SETTINGS.DELETE_ACCOUNT.INPUT_PASSWORD_LABEL
)
)
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.INPUT_PASSWORD_LABEL))
.then(
type(selectors.SETTINGS_DELETE_ACCOUNT.INPUT_PASSWORD, PASSWORD)
)
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.CANCEL_BUTTON))
.then(pollUntilHiddenByQSA(selectors.SETTINGS_DELETE_ACCOUNT.DETAILS))
.then(
testElementTextInclude(selectors.SETTINGS.PROFILE_HEADER, email)
)
);
},
'navigate directly to delete account, sign in': function () {
return (
this.remote
.then(openPage(DELETE_ACCOUNT_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS_DELETE_ACCOUNT.DETAILS))
// Intern won't click on checkboxes with SVGs on top. So click the
// checkbox labels instead :-\
.findAllByCssSelector(selectors.SETTINGS_DELETE_ACCOUNT.CHECKBOXES)
.then((labels) => labels.map((label) => label.click()))
.end()
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.SUBMIT_BUTTON))
.then(
testElementExists(
selectors.SETTINGS.DELETE_ACCOUNT.INPUT_PASSWORD_LABEL
)
)
.then(click(selectors.SETTINGS.DELETE_ACCOUNT.INPUT_PASSWORD_LABEL))
.then(
type(selectors.SETTINGS_DELETE_ACCOUNT.INPUT_PASSWORD, PASSWORD)
)
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.CONFIRM))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
);
},
},
});

Просмотреть файл

@ -1,171 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const intern = require('intern').default;
const assert = intern.getPlugin('chai').assert;
const { describe, it, beforeEach } = intern.getPlugin('interface.bdd');
const selectors = require('../lib/selectors');
const FunctionalHelpers = require('../lib/helpers');
const FunctionalSettingsHelpers = require('./lib/helpers');
const { navigateToSettingsV2 } = FunctionalSettingsHelpers;
const {
click,
getWebChannelMessageData,
storeWebChannelMessageData,
testElementTextEquals,
testElementTextInclude,
type,
} = FunctionalHelpers.helpersRemoteWrapped;
const CHANGE_PROFILE_COMMAND = 'profile:change';
describe('display name', () => {
let email;
beforeEach(async ({ remote }) => {
email = await navigateToSettingsV2(remote);
await click(
selectors.SETTINGS.DISPLAY_NAME.ADD_BUTTON,
selectors.SETTINGS.DISPLAY_NAME.TEXTBOX_LABEL,
remote
);
await type(
selectors.SETTINGS.DISPLAY_NAME.TEXTBOX_FIELD,
'Test User',
{},
remote
);
});
it('can add a display name', async ({ remote }) => {
await click(selectors.SETTINGS.DISPLAY_NAME.SUBMIT_BUTTON, remote);
// Verify the saved name is displayed
await testElementTextEquals(
selectors.SETTINGS.DISPLAY_NAME.SAVED_DISPLAY_NAME,
'Test User',
remote
);
// Also check the avatar dropdown displays the saved name
await click(selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON, remote);
await testElementTextInclude(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.DISPLAY_NAME_LABEL,
'Test User',
remote
);
});
it('can click cancel and not add a display name', async ({ remote }) => {
// Click cancel without providing a display name
await click(
selectors.SETTINGS.DISPLAY_NAME.CANCEL_BUTTON,
selectors.SETTINGS.HEADER,
remote
);
// Verify the display name is not saved
await testElementTextEquals(
selectors.SETTINGS.DISPLAY_NAME.SAVED_DISPLAY_NAME,
'None',
remote
);
// Also check the avatar dropdown displays the email id
await click(selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON, remote);
await testElementTextInclude(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.DISPLAY_NAME_LABEL,
email,
remote
);
});
it('can change a display name', async ({ remote }) => {
await storeWebChannelMessageData(CHANGE_PROFILE_COMMAND, remote);
await click(selectors.SETTINGS.DISPLAY_NAME.SUBMIT_BUTTON, remote);
// Click change and change the display name
await click(selectors.SETTINGS.DISPLAY_NAME.ADD_BUTTON, remote);
await type(
selectors.SETTINGS.DISPLAY_NAME.TEXTBOX_FIELD,
'New User',
{},
remote
);
await click(selectors.SETTINGS.DISPLAY_NAME.SUBMIT_BUTTON, remote);
const msg = await getWebChannelMessageData(CHANGE_PROFILE_COMMAND, remote);
assert.equal(msg.command, CHANGE_PROFILE_COMMAND);
assert.isString(msg.data.uid);
// Verify the saved name is displayed
await testElementTextEquals(
selectors.SETTINGS.DISPLAY_NAME.SAVED_DISPLAY_NAME,
'New User',
remote
);
// Also check the avatar dropdown displays the saved name
await click(selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON, remote);
await testElementTextInclude(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.DISPLAY_NAME_LABEL,
'New User',
remote
);
});
it('can click cancel and not change display name', async ({ remote }) => {
await click(selectors.SETTINGS.DISPLAY_NAME.SUBMIT_BUTTON, remote);
// Click change to change the display name
await click(selectors.SETTINGS.DISPLAY_NAME.ADD_BUTTON, remote);
await type(
selectors.SETTINGS.DISPLAY_NAME.TEXTBOX_FIELD,
'New User',
{},
remote
);
// Click cancel and don't save the new display name
await click(selectors.SETTINGS.DISPLAY_NAME.CANCEL_BUTTON, remote);
// Verify the previous name is displayed
await testElementTextEquals(
selectors.SETTINGS.DISPLAY_NAME.SAVED_DISPLAY_NAME,
'Test User',
remote
);
// Also check the avatar dropdown displays the saved name
await click(selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON, remote);
await testElementTextInclude(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.DISPLAY_NAME_LABEL,
'Test User',
remote
);
});
it('can remove a display name', async ({ remote }) => {
await click(selectors.SETTINGS.DISPLAY_NAME.SUBMIT_BUTTON, remote);
// Click change to change the display name
await click(selectors.SETTINGS.DISPLAY_NAME.ADD_BUTTON, remote);
await type(selectors.SETTINGS.DISPLAY_NAME.TEXTBOX_FIELD, '', {}, remote);
// Click submit without providing a display name
await click(selectors.SETTINGS.DISPLAY_NAME.SUBMIT_BUTTON, remote);
// Verify there is no display name
await testElementTextEquals(
selectors.SETTINGS.DISPLAY_NAME.SAVED_DISPLAY_NAME,
'None',
remote
);
// Also check the avatar dropdown displays email id
await click(selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON, remote);
await testElementTextInclude(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.DISPLAY_NAME_LABEL,
email,
remote
);
});
});

Просмотреть файл

@ -1,75 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const intern = require('intern').default;
const config = intern._config;
const SETTINGS_URL = config.fxaSettingsV2Root;
const { describe, it, beforeEach } = intern.getPlugin('interface.bdd');
const selectors = require('../lib/selectors');
const FunctionalHelpers = require('../lib/helpers');
const { createEmail } = FunctionalHelpers;
const FunctionalSettingsHelpers = require('./lib/helpers');
const { navigateToSettingsV2 } = FunctionalSettingsHelpers;
describe('external links', () => {
let primaryEmail,
testHrefEquals,
testHrefIncludes,
testElementExists,
clearBrowserState,
openPage,
subscribeAndSigninToRp;
beforeEach(async ({ remote }) => {
({
clearBrowserState,
testHrefEquals,
testHrefIncludes,
testElementExists,
openPage,
subscribeAndSigninToRp,
} = FunctionalHelpers.applyRemote(remote));
await clearBrowserState();
primaryEmail = await navigateToSettingsV2(remote);
});
it('renders external links correctly', async () => {
await testElementExists(selectors.SETTINGS.NAVIGATION.NEWSLETTERS_LINK);
await testHrefIncludes(
selectors.SETTINGS.NAVIGATION.NEWSLETTERS_LINK,
encodeURIComponent(primaryEmail)
);
await testElementExists(selectors.SETTINGS.FOOTER.PRIVACY_LINK);
await testHrefEquals(
selectors.SETTINGS.FOOTER.PRIVACY_LINK,
'https://www.mozilla.org/en-US/privacy/websites/'
);
await testElementExists(selectors.SETTINGS.FOOTER.TERMS_LINK);
await testHrefEquals(
selectors.SETTINGS.FOOTER.TERMS_LINK,
'https://www.mozilla.org/en-US/about/legal/terms/services/'
);
});
it('renders Subscriptions link in navigation when we are subscribed to a product', async function () {
if (process.env.CIRCLECI === 'true' && !process.env.SUBHUB_STRIPE_APIKEY) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
await subscribeAndSigninToRp(email);
await openPage(SETTINGS_URL, selectors.SETTINGS.APP);
// test
await testElementExists(selectors.SETTINGS.NAVIGATION.SUBSCRIPTIONS_LINK);
await testHrefEquals(
selectors.SETTINGS.NAVIGATION.SUBSCRIPTIONS_LINK,
`/subscriptions`
);
});
});

Просмотреть файл

@ -1,34 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const selectors = require('../../lib/selectors');
const FunctionalHelpers = require('../../lib/helpers');
const { createEmail } = FunctionalHelpers;
const config = intern._config;
const EMAIL_FIRST = config.fxaContentRoot;
const password = 'passwordzxcv';
const {
clearBrowserState,
createUser,
openPage,
fillOutEmailFirstSignIn,
testElementExists,
} = FunctionalHelpers.helpersRemoteWrapped;
async function navigateToSettingsV2(remote) {
const email = createEmail();
await clearBrowserState(remote);
await createUser(email, password, { preVerified: true }, remote);
await openPage(EMAIL_FIRST, selectors.ENTER_EMAIL.HEADER, remote);
await fillOutEmailFirstSignIn(email, password, remote);
await testElementExists(selectors.SETTINGS.APP, remote);
return email;
}
module.exports = {
navigateToSettingsV2,
};

Просмотреть файл

@ -1,316 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('../lib/helpers');
const selectors = require('../lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const RESET_PASSWORD_URL =
config.fxaContentRoot + 'reset_password?context=fx_desktop_v3&service=sync';
const PASSWORD = 'passwordzxcv';
const NEW_PASSWORD = '()()():|';
let email, recoveryKey;
const {
createEmail,
createUser,
clearBrowserState,
click,
fillOutCompleteResetPassword,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutRecoveryKey,
fillOutResetPassword,
fillOutSignUpCode,
fillOutVerificationCode,
openPage,
openVerificationLinkInSameTab,
testIsBrowserNotified,
testElementExists,
testElementTextInclude,
type,
} = FunctionalHelpers;
registerSuite('Account recovery key', {
beforeEach: function () {
email = createEmail('sync{id}');
const remote = this.remote;
return (
this.remote
.then(clearBrowserState({ forceAll: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testElementTextInclude(selectors.RECOVERY_KEY.STATUS, 'Not set'))
// Complete the steps to add an account recovery key
.then(
click(
selectors.RECOVERY_KEY.GENERATE_KEY_BUTTON,
selectors.RECOVERY_KEY.PASSWORD_INPUT_LABEL
)
) // recovery-key-unit-row-rouote
// Once again, click the label first to get it out of the way
.then(
click(
selectors.RECOVERY_KEY.PASSWORD_INPUT_LABEL,
selectors.RECOVERY_KEY.PASSWORD_INPUT
)
)
.then(click(selectors.RECOVERY_KEY.PASSWORD_INPUT))
.then(type(selectors.RECOVERY_KEY.PASSWORD_INPUT, PASSWORD))
.then(
click(
selectors.RECOVERY_KEY.CONFIRM_PASSWORD_CONTINUE,
selectors.RECOVERY_KEY.RECOVERY_KEY_TEXT
)
) // continue-button
.then(testElementExists(selectors.RECOVERY_KEY.RECOVERY_KEY_TEXT))
// Store the key to be used later
.findByCssSelector(selectors.RECOVERY_KEY.RECOVERY_KEY_TEXT)
.getVisibleText()
.then((key) => {
recoveryKey = key;
return remote.then(
click(
selectors.RECOVERY_KEY.RECOVERY_KEY_DONE_BUTTON,
selectors.RECOVERY_KEY.STATUS
)
);
})
.end()
.then(testElementTextInclude(selectors.RECOVERY_KEY.STATUS, 'Enabled'))
);
},
tests: {
'can revoke account recovery key': function () {
const remote = this.remote;
let secondKey;
return (
this.remote
.then(
click(
selectors.SETTINGS.SECURITY.RECOVERY_KEY.REMOVE_RECOVERY_KEY,
selectors.RECOVERY_KEY.CONFIRM_REVOKE_DESCRIPTION
)
)
.then(
testElementExists(selectors.RECOVERY_KEY.CONFIRM_REVOKE_DESCRIPTION)
)
.then(
click(
selectors.RECOVERY_KEY.CONFIRM_REVOKE_OK,
selectors.RECOVERY_KEY.STATUS
)
)
// Unfortunately need a delay here because no elements are added/removed that we can
// wait on to check the text.
.sleep(1000)
.then(
testElementTextInclude(selectors.RECOVERY_KEY.STATUS, 'Not set')
)
// create a new account recovery key
.then(click(selectors.RECOVERY_KEY.GENERATE_KEY_BUTTON))
.then(click(selectors.RECOVERY_KEY.PASSWORD_INPUT_LABEL))
.then(type(selectors.RECOVERY_KEY.PASSWORD_INPUT, PASSWORD))
.then(click(selectors.RECOVERY_KEY.CONFIRM_PASSWORD_CONTINUE))
.then(testElementExists(selectors.RECOVERY_KEY.RECOVERY_KEY_TEXT))
.findByCssSelector(selectors.RECOVERY_KEY.RECOVERY_KEY_TEXT)
.getVisibleText()
.then((key) => {
secondKey = key;
return remote.then(
click(selectors.RECOVERY_KEY.RECOVERY_KEY_DONE_BUTTON)
);
})
.end()
.then(
testElementTextInclude(selectors.RECOVERY_KEY.STATUS, 'Enabled')
)
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 4))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.HEADER
)
)
// enter old key and check for error tooltip
.then(fillOutRecoveryKey(recoveryKey))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.TOOLTIP
)
)
// enter the new key
.then(() => {
return remote.then(fillOutRecoveryKey(secondKey));
})
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(NEW_PASSWORD, NEW_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.SUB_HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
// For good measure, lets re-login with new password
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, NEW_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'can reset password with account recovery key': function () {
return (
this.remote
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 2))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.HEADER
)
)
// enter invalid account recovery key
.then(fillOutRecoveryKey('N8TVALID'))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.TOOLTIP
)
)
.then(fillOutRecoveryKey(recoveryKey))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(NEW_PASSWORD, NEW_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.SUB_HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
// For good measure, lets re-login with new password
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, NEW_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'can reset password when forgot account recovery key': function () {
return (
this.remote
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 2))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.HEADER
)
)
.then(click(selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.LOST_KEY))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(NEW_PASSWORD, NEW_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.SUB_HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
// For good measure, lets re-login with new password
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, NEW_PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'can not re-use account recovery key': function () {
return (
this.remote
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 2))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD_RECOVERY_KEY.HEADER
)
)
.then(fillOutRecoveryKey(recoveryKey))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(NEW_PASSWORD, NEW_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.SUB_HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
// Attempt to re-use reset link, shows expired link
.then(openVerificationLinkInSameTab(email, 2))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD.EXPIRED_LINK_HEADER
)
)
);
},
},
});
registerSuite('Account recovery key - unverified session', {
beforeEach: function () {
email = createEmail('sync{id}');
return (
this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }))
// when an account is created, the original session is verified
// re-login to destroy original session and created an unverified one
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
);
},
tests: {
'gated in unverified session open verification same tab': function () {
return (
this.remote
// send and open verification in same tab
.then(click(selectors.RECOVERY_KEY.GENERATE_KEY_BUTTON))
// if the session is unverified, then the modal will be shown.
.then(testElementExists('[data-testid=modal-verify-session]'))
.then(fillOutVerificationCode(email, 1))
.then(
testElementExists(
selectors.SETTINGS.SECURITY.RECOVERY_KEY.PASSWORD_TEXTBOX_LABEL
)
)
);
},
},
});

Просмотреть файл

@ -1,127 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const intern = require('intern').default;
const { describe, it, beforeEach } = intern.getPlugin('interface.bdd');
const selectors = require('../lib/selectors');
const FunctionalHelpers = require('../lib/helpers');
const { createEmail } = FunctionalHelpers;
const FunctionalSettingsHelpers = require('./lib/helpers');
const { navigateToSettingsV2 } = FunctionalSettingsHelpers;
describe('secondary email', () => {
let primaryEmail;
const secondaryEmail = createEmail();
let click,
getEmailCode,
testElementExists,
testElementTextInclude,
type,
visibleByQSA;
beforeEach(async ({ remote }) => {
({
click,
getEmailCode,
testElementExists,
testElementTextInclude,
type,
visibleByQSA,
} = FunctionalHelpers.applyRemote(remote));
primaryEmail = await navigateToSettingsV2(remote);
});
it('can add and verify secondary email', async () => {
await click(
selectors.SETTINGS.SECONDARY_EMAIL.ADD_BUTTON,
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_LABEL
);
// try adding the primary as the secondary
await click(
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_LABEL,
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_FIELD
);
await type(selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_FIELD, primaryEmail);
await click(
selectors.SETTINGS.SECONDARY_EMAIL.SUBMIT_BUTTON,
selectors.SETTINGS.TOOLTIP
);
await testElementTextInclude(
selectors.SETTINGS.TOOLTIP,
'secondary email must be different than your account email'
);
// add secondary email, resend, remove
await click(
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_LABEL,
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_FIELD
);
await type(selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_FIELD, secondaryEmail);
await click(selectors.SETTINGS.SECONDARY_EMAIL.SUBMIT_BUTTON);
await testElementTextInclude(
selectors.SETTINGS.SECONDARY_EMAIL.FORM,
secondaryEmail
);
await click(
selectors.SETTINGS.BACK_BUTTON,
selectors.SETTINGS.SECONDARY_EMAIL.HEADER_VALUE
);
await testElementTextInclude(
selectors.SETTINGS.SECONDARY_EMAIL.HEADER_VALUE,
secondaryEmail
);
await testElementTextInclude(
selectors.SETTINGS.SECONDARY_EMAIL.HEADER_VALUE,
'unconfirmed'
);
await testElementExists(selectors.SETTINGS.SECONDARY_EMAIL.DELETE_BUTTON);
await testElementExists(selectors.SETTINGS.SECONDARY_EMAIL.REFRESH_BUTTON);
await click(
selectors.SETTINGS.SECONDARY_EMAIL.DELETE_BUTTON,
selectors.SETTINGS.SECONDARY_EMAIL.ADD_BUTTON
);
// add and verify
await click(
selectors.SETTINGS.SECONDARY_EMAIL.ADD_BUTTON,
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_LABEL
);
await click(
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_LABEL,
selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_FIELD
);
await type(selectors.SETTINGS.SECONDARY_EMAIL.EMAIL_FIELD, secondaryEmail);
await click(selectors.SETTINGS.SECONDARY_EMAIL.SUBMIT_BUTTON);
const verifyCode = await getEmailCode(secondaryEmail, 1);
await click(
selectors.SETTINGS.SECONDARY_EMAIL.VERIFY_FORM_LABEL,
selectors.SETTINGS.SECONDARY_EMAIL.VERIFY_FIELD
);
await type(selectors.SETTINGS.SECONDARY_EMAIL.VERIFY_FIELD, verifyCode);
await click(
selectors.SETTINGS.SECONDARY_EMAIL.VERIFY_FORM_SUBMIT_BUTTON,
selectors.SETTINGS.SECONDARY_EMAIL.DELETE_BUTTON
);
await testElementExists(selectors.SETTINGS.SECONDARY_EMAIL.DELETE_BUTTON);
await testElementExists(selectors.SETTINGS.SECONDARY_EMAIL.MAKE_PRIMARY);
// swap primary and secondary
await click(
selectors.SETTINGS.SECONDARY_EMAIL.MAKE_PRIMARY,
selectors.EMAIL.SUCCESS
);
await visibleByQSA(selectors.EMAIL.SUCCESS);
await testElementTextInclude(
selectors.SETTINGS.PRIMARY_EMAIL.HEADER_VALUE,
secondaryEmail
);
await testElementTextInclude(
selectors.SETTINGS.SECONDARY_EMAIL.HEADER_VALUE,
primaryEmail
);
});
});

Просмотреть файл

@ -1,325 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const { testElementDisabled } = require('../lib/helpers');
const FunctionalHelpers = require('../lib/helpers');
const selectors = require('../lib/selectors');
const config = intern._config;
const SETTINGS_URL = `${config.fxaContentRoot}settings`;
const PASSWORD = 'passwordzxcv';
const SYNC_ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync`;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?action=email`;
const RECOVERY_CODES_URL = `${config.fxaContentRoot}settings/two_step_authentication/replace_codes`;
const RESET_PASSWORD_URL = `${config.fxaContentRoot}reset_password?context=fx_desktop_v3&service=sync`;
let email;
let secret;
const {
confirmTotpCode,
clearBrowserState,
click,
createEmail,
createUser,
fillOutCompleteResetPassword,
fillOutDeleteAccount,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutResetPassword,
fillOutSignUpCode,
fillOutVerificationCode,
generateTotpCode,
openPage,
openVerificationLinkInNewTab,
openVerificationLinkInSameTab,
signOut,
switchToWindow,
testElementExists,
testElementTextInclude,
testIsBrowserNotified,
testSuccessWasShown,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('TOTP', {
beforeEach: function () {
email = createEmail();
return (
this.remote
.then(clearBrowserState({ force: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.TOTP.MENU_BUTTON))
.then(click(selectors.TOTP.MENU_BUTTON))
.then(testElementExists(selectors.TOTP.QR_CODE))
.then(testElementExists(selectors.TOTP.SHOW_CODE_LINK))
.then(click(selectors.TOTP.SHOW_CODE_LINK))
.then(testElementExists(selectors.TOTP.MANUAL_CODE))
// Store the secret key to recalculate the code later
.findByCssSelector(selectors.TOTP.MANUAL_CODE)
.getVisibleText()
.then((secretKey) => {
secret = secretKey;
})
.end()
.then(() => this.remote.then(click(selectors.TOTP.KEY_OK_BUTTON)))
);
},
tests: {
'can add TOTP to account and confirm web signin': function () {
return (
this.remote
// Shows tool tip for invalid codes on setup
// Note: as usual we have to click the label first, to get it out
// of the way, then we can click into the input.
.then(click(selectors.TOTP.CONFIRM_CODE_INPUT_LABEL))
.then(click(selectors.TOTP.CONFIRM_CODE_INPUT))
.then(type(selectors.TOTP.CONFIRM_CODE_INPUT, '123432'))
.then(click(selectors.TOTP.CONFIRM_CODE_BUTTON))
.then(visibleByQSA(selectors.TOTP.TOOLTIP))
.then(testElementTextInclude(selectors.TOTP.TOOLTIP, 'Incorrect'))
.then(confirmTotpCode(secret))
.then(signOut())
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
// Show tool tip for invalid codes on sign-in
.then(type(selectors.TOTP_SIGNIN.INPUT, '123432'))
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(visibleByQSA(selectors.TOTP.LOGIN_FLOW_TOOLTIP))
.then(
testElementTextInclude(selectors.TOTP.LOGIN_FLOW_TOOLTIP, 'Invalid')
)
// Redirect to /settings when successful
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'can add TOTP to account and confirm sync signin': function () {
return this.remote
.then(confirmTotpCode(secret))
.then(signOut())
.then(
openPage(SYNC_ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {},
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER));
},
'can remove TOTP from account and skip confirmation': function () {
return (
this.remote
.then(confirmTotpCode(secret))
// Remove token, first in unit row then in confirmation modal
.then(
click(selectors.TOTP.DELETE_BUTTON, selectors.TOTP.CONFIRM_DELETE)
)
.then(click(selectors.TOTP.CONFIRM_DELETE))
.then(testSuccessWasShown)
.then(testElementExists(selectors.TOTP.MENU_BUTTON))
.refresh()
// Does not prompt for code
.then(signOut())
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'can add TOTP to account and then delete it': function () {
return this.remote
.then(confirmTotpCode(secret))
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.DELETE_ACCOUNT_BUTTON))
.then(visibleByQSA(selectors.SETTINGS_DELETE_ACCOUNT.DETAILS))
.then(fillOutDeleteAccount(PASSWORD))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER));
},
'can change backup authentication codes': function () {
return this.remote
.then(confirmTotpCode(secret))
.then(
openPage(
RECOVERY_CODES_URL,
selectors.TOTP.RECOVERY_CODES_DESCRIPTION
)
)
.then(testElementExists(selectors.SETTINGS.SECURITY.TFA.RECOVERY_CODES))
.findByCssSelector(selectors.SETTINGS.SECURITY.TFA.FIRST_RECOVERY_CODE)
.getVisibleText()
.then((code) => {
return this.remote
.then(click(selectors.SETTINGS.SECURITY.TFA.CONTINUE_RECOVERY_KEY))
.then(
testElementExists(
selectors.SETTINGS.SECURITY.TFA.RECOVERY_KEY_INPUT
)
)
.then(
testElementDisabled(
selectors.SETTINGS.SECURITY.TFA.SUBMIT_RECOVERY_KEY
)
)
.then(
type(selectors.SETTINGS.SECURITY.TFA.RECOVERY_KEY_INPUT, code)
)
.then(click(selectors.SETTINGS.SECURITY.TFA.SUBMIT_RECOVERY_KEY));
});
},
'can reset password, prompt for TOTP and login - same browser same tab':
function () {
return (
this.remote
.then(confirmTotpCode(secret))
.then(signOut())
//.then(clearBrowserState())
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInSameTab(email, 2))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(
click(
selectors.TOTP_SIGNIN.SUBMIT,
selectors.CONNECT_ANOTHER_DEVICE.HEADER
)
)
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.CONNECTED))
);
},
'can reset password, prompt for TOTP and login - same browser different tab':
function () {
return this.remote
.then(confirmTotpCode(secret))
.then(signOut())
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInNewTab(email, 2))
.then(switchToWindow(1))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(
click(
selectors.TOTP_SIGNIN.SUBMIT,
selectors.CONNECT_ANOTHER_DEVICE.HEADER
)
)
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.CONNECTED));
},
'can reset password, prompt for TOTP and login - verify different browser':
function () {
return (
this.remote
.then(confirmTotpCode(secret))
.then(signOut())
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
// clear all browser state, simulate opening in a new browser
.then(clearBrowserState({ force: true }))
.then(openVerificationLinkInSameTab(email, 2))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(type(selectors.TOTP_SIGNIN.INPUT, generateTotpCode(secret)))
.then(click(selectors.TOTP_SIGNIN.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
},
});
registerSuite('TOTP - unverified session', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState({ force: true }));
},
tests: {
'gated in unverified session open verification same tab': function () {
return (
this.remote
// when an account is created, the original session is verified
// re-login to destroy original session and created an unverified one
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP.UNLOCK_BUTTON))
// unlock panel
.then(click(selectors.TOTP.UNLOCK_BUTTON))
.then(testElementExists(selectors.TOTP.UNLOCK_SEND_VERIFY))
// send and open verification in same tab
.then(fillOutVerificationCode(email, 1))
// panel becomes verified and can be opened
.then(
testElementExists(
selectors.SETTINGS.SECURITY.TFA.SECURITY_CODE_TEXTBOX_LABEL
)
)
);
},
},
});

Просмотреть файл

@ -1,204 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const fxaProduction = intern._config.fxaProduction;
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const PASSWORD = 'passwordcxzv';
let email;
const {
clearBrowserState,
click,
closeCurrentWindow,
createEmail,
createUser,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
openPage,
openTab,
signOut,
switchToWindow,
testAttributeMatches,
testElementExists,
testElementTextInclude,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('signin', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState());
},
tests: {
'signin verified with incorrect password, click `forgot password?`': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, 'incorrect password'))
// success is seeing the error message.
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.TOOLTIP))
// If user clicks on "forgot your password?",
// begin the reset password flow.
.then(click(selectors.SIGNIN_PASSWORD.LINK_FORGOT_PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD.HEADER))
);
},
'signin with email with leading space strips space': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(' ' + email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'signin with email with trailing space strips space': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email + ' ', PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'signin verified with password that incorrectly has leading whitespace': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, ' ' + PASSWORD))
// success is seeing the error message.
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.TOOLTIP))
.then(
testElementTextInclude(
selectors.SIGNIN_PASSWORD.TOOLTIP,
'password'
)
)
);
},
'signin from second tab while at /': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(openTab(ENTER_EMAIL_URL))
.then(switchToWindow(1))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(closeCurrentWindow())
.then(switchToWindow(0))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'signin from second tab while at /signin': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNIN_PASSWORD.HEADER)
)
.then(openTab(ENTER_EMAIL_URL))
.then(switchToWindow(1))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(closeCurrentWindow())
.then(switchToWindow(0))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'signin from second tab while at /signup': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
)
.then(openTab(ENTER_EMAIL_URL))
.then(switchToWindow(1))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(closeCurrentWindow())
.then(switchToWindow(0))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'login as an existing user': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
// success is seeing the header
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(signOut())
// login as existing user
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNIN.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN.SUBMIT))
// success is seeing the existing user logged in
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'data-flow-begin attribute is set': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(
testAttributeMatches('body', 'data-flow-begin', /^[1-9][0-9]{12,}$/)
);
},
'integrity attribute is set on scripts and css': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(testAttributeMatches('script', 'integrity', /^sha512-/))
.then(testAttributeMatches('link', 'integrity', /^sha512-/))
.catch(function (err) {
// this tests only in production
if (fxaProduction || err.name !== 'AssertionError') {
throw err;
}
});
},
},
});

Просмотреть файл

@ -1,452 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const PASSWORD = 'passwordcxvz';
let email;
const {
addAndVerifySecondaryEmail,
clearBrowserState,
click,
closeCurrentWindow,
createEmail,
createUser,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
fillOutEmailFirstSignIn,
fillOutSignInTokenCode,
fillOutSignInUnblock,
getUnblockInfo,
openPage,
openTab,
signOut,
switchToWindow,
testElementTextEquals,
testErrorTextInclude,
testElementExists,
testElementTextInclude,
testSuccessWasShown,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('signin blocked', {
beforeEach: function () {
email = createEmail('blocked{id}');
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState({ forceAll: true }));
},
tests: {
'valid code entered': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(fillOutSignInUnblock(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'valid code with whitespace at the beginning entered': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
return this.parent.then(
type(
selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE,
' ' + unblockInfo.unblockCode
)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'valid code with whitespace at the end entered': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
return this.parent.then(
type(
selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE,
unblockInfo.unblockCode + ' '
)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'invalid code entered': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(type(selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE, 'i'))
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(visibleByQSA(selectors.SIGNIN_UNBLOCK.TOOLTIP))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.TOOLTIP, 'invalid')
);
},
'incorrect code entered': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(type(selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE, 'incorrec'))
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(visibleByQSA(selectors.SIGNIN_UNBLOCK.ERROR))
.then(testErrorTextInclude('invalid'))
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
return this.parent.then(
type(selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE, unblockInfo.unblockCode)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'incorrect password entered': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, 'incorrect'))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(fillOutSignInUnblock(email, 0))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(testErrorTextInclude('incorrect password'))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(
testElementTextInclude(selectors.SIGNIN_UNBLOCK.VERIFICATION, email)
)
.then(fillOutSignInUnblock(email, 0))
// the first code is no longer valid, must use the 2nd.
.then(visibleByQSA(selectors.SIGNIN_UNBLOCK.ERROR))
.then(testErrorTextInclude('invalid'))
// get and consume the second code
.then(fillOutSignInUnblock(email, 1))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
resend: function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(click(selectors.SIGNIN_UNBLOCK.LINK_RESEND))
.then(visibleByQSA('.success'))
.then(testElementTextInclude('.success', 'resent'))
// use the 2nd unblock code
.then(fillOutSignInUnblock(email, 1))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'report signin success': function () {
let unblockCode;
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
unblockCode = unblockInfo.unblockCode;
return this.parent.then(openTab(unblockInfo.reportSignInLink));
})
.then(switchToWindow(1))
.then(testElementExists(selectors.REPORT_SIGNIN.HEADER))
.then(click(selectors.REPORT_SIGNIN.SUBMIT))
.then(testElementExists(selectors.SIGNIN_REPORTED.HEADER))
.then(closeCurrentWindow())
// try to use the code that was reported, it should error
.then(function () {
return this.parent.then(
type(selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE, unblockCode)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(visibleByQSA(selectors.SIGNIN_UNBLOCK.ERROR))
.then(testErrorTextInclude('invalid'))
);
},
'report signin link unblockCode broken': function () {
let unblockCode;
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
unblockCode = unblockInfo.unblockCode;
const invalidLink = unblockInfo.reportSignInLink.replace(
/unblockCode=[^&]+/,
'unblockCode=invalid_code'
);
return this.parent.then(openTab(invalidLink));
})
.then(switchToWindow(1))
.then(testElementExists('#fxa-report-sign-in-link-damaged-header'))
.then(closeCurrentWindow())
// code can still be used
.then(function () {
return this.parent.then(
type(selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE, unblockCode)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'report signin link uid broken': function () {
let unblockCode;
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
unblockCode = unblockInfo.unblockCode;
const invalidLink = unblockInfo.reportSignInLink.replace(
/uid=[^&]+/,
'uid=invalid_uid'
);
return this.parent.then(openTab(invalidLink));
})
.then(switchToWindow(1))
.then(testElementExists('#fxa-report-sign-in-link-damaged-header'))
.then(closeCurrentWindow())
// code can still be used
.then(function () {
return this.parent.then(
type(selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE, unblockCode)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'report link opened after code used': function () {
let reportSignInLink;
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(getUnblockInfo(email, 0))
.then(function (unblockInfo) {
reportSignInLink = unblockInfo.reportSignInLink;
return this.parent.then(
type(
selectors.SIGNIN_UNBLOCK.UNBLOCK_CODE,
unblockInfo.unblockCode
)
);
})
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(function () {
return this.parent.then(
openPage(reportSignInLink, '#fxa-report-sign-in-header')
);
})
// report link is expired and can no longer be used.
.then(click(selectors.SIGNIN_UNBLOCK.SUBMIT))
.then(visibleByQSA(selectors.SIGNIN_UNBLOCK.ERROR))
.then(testErrorTextInclude('invalid'))
);
},
unverified: function () {
email = createEmail('blocked{id}');
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: false }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
// email 0 is the signup email, email 1 contains the code
.then(fillOutSignInUnblock(email, 1))
// It's substandard UX, but we decided to punt on making
// users verified until v2. When submitting an unblock code
// verifies unverified users, they will not need to enter
// the verification code, instead they'll go directly
// to the settings page.
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignInTokenCode(email, 2))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'with primary email changed': function () {
email = createEmail('{id}');
const secondaryEmail = createEmail('blocked{id}');
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(click(selectors.EMAIL.MENU_BUTTON))
.then(addAndVerifySecondaryEmail(secondaryEmail))
.then(testSuccessWasShown())
// set new primary email
.then(
click(
selectors.SETTINGS.SECONDARY_EMAIL.MAKE_PRIMARY,
selectors.EMAIL.SUCCESS
)
)
.then(
testElementTextEquals(selectors.EMAIL.ADDRESS_LABEL, secondaryEmail)
)
.then(signOut())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
// Try login with new primary email
.then(fillOutEmailFirstSignIn(secondaryEmail, PASSWORD))
.then(
testElementTextInclude(
selectors.SIGNIN_UNBLOCK.VERIFICATION,
secondaryEmail
)
)
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(fillOutSignInUnblock(email, 3))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'with primary email changed incorrect password': function () {
email = createEmail('{id}');
const secondaryEmail = createEmail('blocked{id}');
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(click(selectors.EMAIL.MENU_BUTTON))
.then(addAndVerifySecondaryEmail(secondaryEmail))
.then(testSuccessWasShown())
// set new primary email
.then(
click(
selectors.SETTINGS.SECONDARY_EMAIL.MAKE_PRIMARY,
selectors.EMAIL.SUCCESS
)
)
.then(
testElementTextEquals(selectors.EMAIL.ADDRESS_LABEL, secondaryEmail)
)
.then(signOut())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
// Try login with new primary email and invalid
.then(fillOutEmailFirstSignIn(secondaryEmail, 'invalid pw'))
.then(
testElementTextInclude(
selectors.SIGNIN_UNBLOCK.VERIFICATION,
secondaryEmail
)
)
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(fillOutSignInUnblock(secondaryEmail, 3))
.then(visibleByQSA(selectors.SIGNIN_UNBLOCK.ERROR))
.then(testErrorTextInclude('incorrect password'))
);
},
},
});

Просмотреть файл

@ -1,410 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const assert = intern.getPlugin('chai').assert;
const FunctionalHelpers = require('./lib/helpers');
const { FX_DESKTOP_V3_CONTEXT } = require('../../app/scripts/lib/constants');
const selectors = require('./lib/selectors');
const userAgent = require('./lib/ua-strings');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const PAGE_ENTER_EMAIL_SYNC_DESKTOP = `${config.fxaContentRoot}?context=${FX_DESKTOP_V3_CONTEXT}&service=sync`;
const PASSWORD = 'password12345678';
let email;
let email2;
const {
clearBrowserState,
clearSessionStorage,
click,
createEmail,
createUser,
denormalizeStoredEmail,
destroySessionForEmail,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignInTokenCode,
getStoredAccountByEmail,
openPage,
respondToWebChannelMessage,
testElementExists,
testElementTextEquals,
testElementValueEquals,
testIsBrowserNotified,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('cached signin', {
beforeEach: function () {
email = createEmail('sync{id}');
email2 = createEmail();
return this.remote
.then(clearBrowserState({ force: true }))
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(createUser(email2, PASSWORD, { preVerified: true }));
},
tests: {
'sign in twice, on second attempt email will be cached': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
// reset prefill and context
.then(clearSessionStorage())
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'sign in with incorrect email case before normalization fix, on second attempt canonical form is used':
function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
// reset prefill and context
.then(clearSessionStorage())
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
// synthesize signin pre-#4470 with incorrect email case.
// to avoid a timing issue where the de-normalized email was
// being overwritten in localStorage when denormalization was
// done on the settings page, wait for the signin page to load,
// denormalize, then refresh. See #4711
.then(denormalizeStoredEmail(email))
.refresh()
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.SETTINGS.HEADER))
// email is normalized!
.then(
testElementTextEquals(selectors.SETTINGS.PROFILE_HEADER, email)
)
);
},
'sign in once, use a different account': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
// testing to make sure "Use different account" button works
.then(click(selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT))
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
.then(fillOutEmailFirstSignIn(email2, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
// testing to make sure cached signin comes back after a refresh
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT))
.then(testElementExists(selectors.ENTER_EMAIL.EMAIL))
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email2))
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email2
)
)
);
},
'expired cached credentials': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(destroySessionForEmail(email))
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'cached credentials that expire while on page': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(testElementExists(selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE))
.then(destroySessionForEmail(email))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
// Session expired error should show.
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.ERROR))
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'unverified cached signin redirects to confirm email': function () {
const email = createEmail();
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
// cached login should still go to email confirmation screen for unverified accounts
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
// get the second email, the first was sent via fillOutEmailFirstSignUp above.
.then(fillOutSignInTokenCode(email, 1))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
'sign in on desktop then specify a different email on query parameter continues to cache desktop signin':
function () {
return (
this.remote
.then(
openPage(
PAGE_ENTER_EMAIL_SYNC_DESKTOP,
selectors.ENTER_EMAIL.HEADER
)
)
.then(
respondToWebChannelMessage('fxaccounts:can_link_account', {
ok: true,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(
openPage(
ENTER_EMAIL_URL + '?email=' + email2,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(
testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email2)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT))
.then(testElementExists(selectors.SETTINGS.HEADER))
// reset prefill and context
.then(clearSessionStorage())
// testing to make sure cached signin comes back after a refresh
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
.then(click(selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT))
.then(testElementExists(selectors.ENTER_EMAIL.EMAIL))
);
},
'sign in with desktop context then no context, desktop credentials should persist':
function () {
return (
this.remote
.then(
openPage(
PAGE_ENTER_EMAIL_SYNC_DESKTOP,
selectors.ENTER_EMAIL.HEADER
)
)
.then(
respondToWebChannelMessage('fxaccounts:can_link_account', {
ok: true,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
// ensure signin page is visible otherwise credentials might
// not be cleared by clicking #use-different
.then(
openPage(
ENTER_EMAIL_URL,
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT
)
)
.then(visibleByQSA(selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT))
// need to wait for the email field to be visible
// before attempting to sign-in.
.then(visibleByQSA(selectors.ENTER_EMAIL.EMAIL))
.then(fillOutEmailFirstSignIn(email2, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
// reset prefill and context
.then(clearSessionStorage())
// testing to make sure cached signin comes back after a refresh
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
.refresh()
.then(
testElementExists(selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT)
)
.then(
testElementTextEquals(
selectors.SIGNIN_PASSWORD.EMAIL_NOT_EDITABLE,
email
)
)
);
},
'sign in then use cached credentials to sign in again, existing session token should be re-authenticated':
function () {
let accountData1, accountData2;
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(getStoredAccountByEmail(email))
.then((accountData) => {
assert.ok(accountData.sessionToken);
accountData1 = accountData;
})
.then(openPage(ENTER_EMAIL_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(click(selectors.SIGNIN_PASSWORD.SUBMIT_USE_SIGNED_IN))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(getStoredAccountByEmail(email))
.then((accountData) => {
assert.ok(accountData.sessionToken);
accountData2 = accountData;
})
.then(() => {
assert.equal(accountData1.uid, accountData2.uid);
assert.equal(accountData1.sessionToken, accountData2.sessionToken);
});
},
'sign in then use cached credentials to sign in to sync, a new session token should be created':
function () {
let accountData1, accountData2;
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(getStoredAccountByEmail(email))
.then((accountData) => {
assert.ok(accountData.sessionToken);
accountData1 = accountData;
})
.then(
openPage(
PAGE_ENTER_EMAIL_SYNC_DESKTOP,
selectors.SIGNIN_PASSWORD.HEADER,
{
query: {
forceUA: userAgent['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
signedInUser: null,
},
},
}
)
)
.then(respondToWebChannelMessage())
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.SIGNIN_TOKEN_CODE.HEADER
)
)
.then(fillOutSignInTokenCode(email, 1))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(getStoredAccountByEmail(email))
.then((accountData) => {
assert.ok(accountData.sessionToken);
accountData2 = accountData;
})
.then(() => {
assert.equal(accountData1.uid, accountData2.uid);
assert.notEqual(
accountData1.sessionToken,
accountData2.sessionToken
);
});
},
},
});

Просмотреть файл

@ -1,218 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?action=email`;
const SETTINGS_URL = `${config.fxaContentRoot}settings`;
const PASSWORD = 'passwordzxcv';
const SYNC_ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync`;
let email;
let recoveryCode, recoveryCode2;
let secret;
const {
clearBrowserState,
click,
createEmail,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
generateTotpCode,
getEmail,
openPage,
testElementExists,
testElementTextInclude,
testIsBrowserNotified,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('backup authentication code', {
beforeEach: function () {
email = createEmail();
const self = this;
return (
this.remote
.then(clearBrowserState({ force: true }))
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testElementExists(selectors.TOTP.MENU_BUTTON))
.then(click(selectors.TOTP.MENU_BUTTON))
.then(testElementExists(selectors.TOTP.QR_CODE))
.then(testElementExists(selectors.TOTP.SHOW_CODE_LINK))
.then(click(selectors.TOTP.SHOW_CODE_LINK))
.then(testElementExists(selectors.TOTP.MANUAL_CODE))
// Store the secret key to recalculate the code later
.findByCssSelector(selectors.TOTP.MANUAL_CODE)
.getVisibleText()
.then((secretKey) => {
secret = secretKey;
return (
self.remote
.then(
click(
selectors.SETTINGS.SECURITY.TFA.SECURITY_CODE_TEXTBOX_LABEL
)
)
.then(
type(
selectors.TOTP.CONFIRM_CODE_INPUT,
generateTotpCode(secret)
)
)
.then(click(selectors.TOTP.CONFIRM_CODE_BUTTON))
// Store a backup authentication code
.findByCssSelector(
selectors.SETTINGS.SECURITY.TFA.FIRST_RECOVERY_CODE
)
.getVisibleText()
.then((code) => {
recoveryCode = code;
return self.remote
.findByCssSelector(
selectors.SETTINGS.SECURITY.TFA.SECOND_RECOVERY_CODE
)
.getVisibleText()
.then((code) => {
recoveryCode2 = code;
});
})
.then(() => {
return self.remote
.then(
click(selectors.SETTINGS.SECURITY.TFA.CONTINUE_RECOVERY_KEY)
)
.then(
type(selectors.TOTP.CONFIRM_RECOVERY_INPUT, recoveryCode)
)
.then(click(selectors.TOTP.CONFIRM_RECOVERY_BUTTON));
})
);
})
.end()
);
},
tests: {
'can sign-in with backup authentication code - sync': function () {
return (
this.remote
.then(
click(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON,
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.SIGNOUT_BUTTON
)
)
.then(
click(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.SIGNOUT_BUTTON,
selectors.ENTER_EMAIL.HEADER
)
)
.then(
openPage(SYNC_ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {},
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(click(selectors.SIGNIN_RECOVERY_CODE.LINK))
// Fails for invalid code
.then(type(selectors.SIGNIN_RECOVERY_CODE.INPUT, 'invalid!!!!'))
.then(click(selectors.SIGNIN_RECOVERY_CODE.SUBMIT))
.then(visibleByQSA('.tooltip'))
.then(testElementTextInclude('.tooltip', 'invalid'))
.then(type(selectors.SIGNIN_RECOVERY_CODE.INPUT, recoveryCode))
.then(click(selectors.SIGNIN_RECOVERY_CODE.SUBMIT))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
);
},
'can regenerate backup authentication code when low': function () {
return (
this.remote
.then(
click(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.MENU_BUTTON,
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.SIGNOUT_BUTTON
)
)
.then(
click(
selectors.SETTINGS.AVATAR_DROP_DOWN_MENU.SIGNOUT_BUTTON,
selectors.ENTER_EMAIL.HEADER
)
)
.then(
openPage(SYNC_ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {},
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(click(selectors.SIGNIN_RECOVERY_CODE.LINK))
.then(type(selectors.SIGNIN_RECOVERY_CODE.INPUT, recoveryCode))
.then(click(selectors.SIGNIN_RECOVERY_CODE.SUBMIT))
.then(testIsBrowserNotified('fxaccounts:login'))
// Next attempt to use backup authentication code will redirect to
// page where user can generate more backup authentication codes
.then(clearBrowserState({ force: true }))
.then(
openPage(SYNC_ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {},
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.TOTP_SIGNIN.HEADER))
.then(click(selectors.SIGNIN_RECOVERY_CODE.LINK))
.then(type(selectors.SIGNIN_RECOVERY_CODE.INPUT, recoveryCode2))
.then(click(selectors.SIGNIN_RECOVERY_CODE.SUBMIT))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
// User gets an email notifying them to generate new backup authentication codes.
// Clicking the link in email opens the security page
.then(getEmail(email, 3))
.then((emailData) => {
return openPage(
emailData.headers['x-link'],
selectors.SETTINGS.SECURITY.TFA.CHANGE_TFA
);
})
);
},
},
});

Просмотреть файл

@ -1,371 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const selectors = require('./lib/selectors');
const UA_STRINGS = require('./lib/ua-strings');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
let email;
const PASSWORD = 'password12345678';
const {
click,
clearBrowserState,
closeCurrentWindow,
createEmail,
fillOutEmailFirstSignIn,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
noPageTransition,
noSuchElement,
openPage,
openSignUpInNewTab,
pollUntilHiddenByQSA,
signOut,
switchToWindow,
testAttributeIncludes,
testElementExists,
testElementTextEquals,
testElementTextInclude,
testElementValueEquals,
testErrorTextInclude,
testSuccessWasShown,
testUrlInclude,
type,
visibleByQSA,
waitForUrl,
} = require('./lib/helpers');
const ENTER_EMAIL_ENTRYPOINT = `entrypoint=${encodeURIComponent(
'fxa:enter_email'
)}`;
var SYNC_CONTEXT_DESKTOP = 'context=fx_desktop_v3';
var SYNC_SERVICE = 'service=sync';
const PRODUCT_URL = `${config.fxaContentRoot}subscriptions/products/${config.testProductId}?signin=true`;
function testAtConfirmScreen(email) {
return function () {
return this.parent
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(
testElementTextInclude(selectors.CONFIRM_SIGNUP_CODE.EMAIL_FIELD, email)
);
};
}
registerSuite('signup here', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'with an invalid email': function () {
return this.remote
.then(
openPage(ENTER_EMAIL_URL + '?email=invalid', selectors['400'].HEADER)
)
.then(testErrorTextInclude('invalid'))
.then(testErrorTextInclude('email'));
},
'with an empty email': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL + '?email=', selectors['400'].HEADER))
.then(testErrorTextInclude('invalid'))
.then(testErrorTextInclude('email'));
},
'signup, verify and sign out of two accounts, all in the same tab, then sign in to the first account':
function () {
// https://github.com/mozilla/fxa-content-server/issues/2209
var secondEmail = createEmail();
this.timeout = 90000;
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testSuccessWasShown())
.then(signOut())
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(secondEmail, PASSWORD))
.then(testAtConfirmScreen(secondEmail))
.then(fillOutSignUpCode(secondEmail, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testSuccessWasShown())
.then(signOut())
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'signup with email with leading whitespace on the email': function () {
var emailWithoutSpace = email;
var emailWithSpace = ' ' + email;
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(emailWithSpace, PASSWORD))
.then(testAtConfirmScreen(emailWithoutSpace))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(emailWithoutSpace, PASSWORD))
// user is not confirmed, success is seeing the confirm screen.
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
);
},
'signup with email with trailing whitespace on the email': function () {
var emailWithoutSpace = email;
var emailWithSpace = ' ' + email;
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(emailWithSpace, PASSWORD))
.then(testAtConfirmScreen(emailWithoutSpace))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(emailWithoutSpace, PASSWORD))
// user is not confirmed, success is seeing the confirm screen.
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
);
},
'signup with invalid email address': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, `${email}-`))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
// wait five seconds to allow any errant navigation to occur
.then(noPageTransition(selectors.ENTER_EMAIL.HEADER))
// the validation tooltip should be visible
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP))
);
},
'coppa is empty': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD, { age: ' ' }))
// navigation should not occur
.then(noPageTransition(selectors.SIGNUP_PASSWORD.HEADER))
// an error should be visible
.then(visibleByQSA(selectors.SIGNUP_PASSWORD.TOOLTIP_AGE_REQUIRED))
);
},
'coppa is too young': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD, { age: 12 }))
// should have navigated to cannot-create-account view
.then(testElementExists(selectors.COPPA.HEADER))
);
},
'visiting the pp links saves information for return': function () {
// Skip for now, we'll need to account for this in the React signup epic
// if we want to keep this functionality
this.skip();
return testRepopulateFields.call(
this,
'/legal/terms',
selectors.TOS.HEADER
);
},
'visiting the tos links saves information for return': function () {
// Skip for now, we'll need to account for this in the React signup epic
// if we want to keep this functionality
this.skip();
return testRepopulateFields.call(
this,
'/legal/privacy',
selectors.PRIVACY_POLICY.HEADER
);
},
'form prefill information is cleared after signup->sign out': function () {
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(fillOutSignUpCode(email, 0))
// The original tab should transition to the settings page w/ success
// message.
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(signOut())
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// check the email address was cleared
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, ''))
.then(type(selectors.ENTER_EMAIL.EMAIL, createEmail()))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
// check the password was cleared
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.PASSWORD, ''))
);
},
'signup, open sign-up in second tab, verify in original tab': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(openSignUpInNewTab())
.then(switchToWindow(1))
.then(testElementExists(selectors.SIGNIN_PASSWORD.HEADER))
.then(switchToWindow(0))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(switchToWindow(1))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(closeCurrentWindow());
},
'signup via product page and redirect after confirm': async function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
// Depending on timing the final page might be the redirect page (PRODUCT_URL),
// or might be the product page (which is a URL that ends the same, but has a
// different domain), so we test for the path only:
const productUrlPath = new URL(PRODUCT_URL).pathname;
return this.remote
.then(openPage(PRODUCT_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(fillOutSignUpCode(email, 0))
.then(waitForUrl((url) => url.includes(productUrlPath)));
},
'signup non matching passwords': function () {
const DROWSSAP = 'drowssap';
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(
fillOutEmailFirstSignUp(email, PASSWORD, { vpassword: DROWSSAP })
)
// wait five seconds to allow any errant navigation to occur
.then(noPageTransition(selectors.SIGNUP_PASSWORD.HEADER))
// the validation tooltip should be visible
.then(
testElementTextEquals(
selectors.SIGNUP_PASSWORD.TOOLTIP,
'Passwords do not match'
)
)
// Tooltip should disappear
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(pollUntilHiddenByQSA(selectors.SIGNUP_PASSWORD.TOOLTIP))
// Tooltip should reappear
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, DROWSSAP))
.then(
testElementTextEquals(
selectors.SIGNUP_PASSWORD.TOOLTIP,
'Passwords do not match'
)
)
// user can enter to next input despite tooltip error
.then(type(selectors.SIGNUP_PASSWORD.AGE, '42'))
);
},
'sync suggestion for Fx Desktop': function () {
return this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: UA_STRINGS['desktop_firefox_58'],
},
})
)
.then(click(selectors.ENTER_EMAIL.LINK_SUGGEST_SYNC))
.then(testElementExists(selectors.ENTER_EMAIL.SYNC_DESCRIPTION))
.then(noSuchElement(selectors.ENTER_EMAIL.LINK_SUGGEST_SYNC))
.then(testUrlInclude(SYNC_CONTEXT_DESKTOP))
.then(testUrlInclude(SYNC_SERVICE))
.then(testUrlInclude(ENTER_EMAIL_ENTRYPOINT));
},
'sync suggestion for everyone else': function () {
return this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: UA_STRINGS['desktop_chrome'],
},
})
)
.then(testElementExists(selectors.ENTER_EMAIL.LINK_SUGGEST_SYNC))
.then(
testAttributeIncludes(
selectors.ENTER_EMAIL.LINK_SUGGEST_SYNC,
'href',
'utm_content=fx-sync-get-started'
)
);
},
},
});
function testRepopulateFields(dest, header) {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER))
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.AGE, '24'))
.then(click('a[href="' + dest + '"]'))
.then(testElementExists(header))
.then(click('.back'))
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.AGE, '24'));
}

Просмотреть файл

@ -1,104 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const PASSWORD = 'passwordzxcv';
let email;
const {
click,
clearBrowserState,
createEmail,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
getFxaClient,
getSignupCode,
openPage,
testElementExists,
testElementTextInclude,
testSuccessWasShown,
type,
visibleByQSA,
} = FunctionalHelpers;
const ENTER_EMAIL_URL = config.fxaContentRoot;
function testAtConfirmScreen(email) {
return function () {
return this.parent
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(
testElementTextInclude(selectors.CONFIRM_SIGNUP_CODE.EMAIL_FIELD, email)
);
};
}
registerSuite('signup with code', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'bounced email': function () {
const client = getFxaClient();
return (
this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(() => client.accountDestroy(email, PASSWORD))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
// expect an error message to already be present on redirect
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP_BOUNCED_EMAIL))
);
},
'valid code then click back': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(testSuccessWasShown())
.goBack()
.then(testElementExists(selectors.SETTINGS.HEADER));
},
'invalid code': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
.then(testAtConfirmScreen(email))
.then(getSignupCode(email, 0))
.then((code) => {
code = code === '123123' ? '123124' : '123123';
return this.remote.then(
type(selectors.SIGNIN_TOKEN_CODE.INPUT, code)
);
})
.then(
click(
selectors.SIGNIN_TOKEN_CODE.SUBMIT,
selectors.SIGNIN_TOKEN_CODE.TOOLTIP
)
)
.then(visibleByQSA(selectors.SIGNIN_TOKEN_CODE.TOOLTIP))
.then(
testElementTextInclude(
selectors.SIGNIN_TOKEN_CODE.TOOLTIP,
'invalid or expired confirmation code'
)
);
},
},
});

Просмотреть файл

@ -1,183 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
/*eslint-disable camelcase */
const productIdNameMap = {
prod_GqM9ToKK62qjkK: '123Done Pro',
prod_FiJ42WCzZNRSbS: 'mozilla vpn',
};
/*eslint-enable camelcase*/
const {
clearBrowserState,
click,
createEmail,
createUserAndLoadSettings,
fillOutFinishAccountSetup,
fillOutEmailFirstSignIn,
getTestProductSubscriptionUrl,
openPage,
openRP,
openVerificationLinkInSameTab,
signInToTestProduct,
subscribeAndSigninToRp,
subscribeToTestProductWithCardNumber,
subscribeToTestProductWithPasswordlessAccount,
testElementExists,
testElementTextInclude,
visibleByQSA,
} = FunctionalHelpers;
const config = intern.config;
const ENTER_EMAIL_PAGE_URL = config.fxaContentRoot;
registerSuite('subscriptions', {
tests: {
'visit product page without signing in, expect to see product name displayed in sub-header':
function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
return this.remote
.then(
clearBrowserState({
'123done': true,
force: true,
})
)
.then(
openPage(
getTestProductSubscriptionUrl(),
selectors.ENTER_EMAIL.HEADER
)
)
.then(
testElementTextInclude(
selectors.ENTER_EMAIL.SUB_HEADER,
`Continue to ${productIdNameMap[intern.config.testProductId]}`
)
);
},
'sign up, subscribe, sign in to verify subscription': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
return this.remote.then(subscribeAndSigninToRp(email));
},
'sign up, failed to subscribe due to expired CC': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
return this.remote
.then(
clearBrowserState({
'123done': true,
force: true,
})
)
.then(createUserAndLoadSettings(email))
.then(signInToTestProduct())
.then(click(selectors['123DONE'].LINK_LOGOUT))
.then(visibleByQSA(selectors['123DONE'].BUTTON_SIGNIN))
.then(subscribeToTestProductWithCardNumber('4000000000000069'))
.then(testElementTextInclude('.payment-error', 'expired'));
},
'sign up, failed to subscribe with mismatching currency': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
return this.remote
.then(
clearBrowserState({
'123done': true,
force: true,
})
)
.then(createUserAndLoadSettings(email))
.then(
subscribeToTestProductWithCardNumber(
'4000000000000069',
getTestProductSubscriptionUrl('myr')
)
)
.then(
testElementTextInclude(
'.payment-error',
'It looks like your credit card has expired.'
)
);
},
'sign up for subscription with password less account': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
const PASSWORD = 'passwordzxcv';
return (
this.remote
.then(
clearBrowserState({
'123done': true,
force: true,
})
)
.then(openRP())
.then(
click(
selectors['123DONE'].BUTTON_SUBSCRIBE_PASSWORDLESS,
'.new-user-email-form'
)
)
.then(
subscribeToTestProductWithPasswordlessAccount(
'4242424242424242',
email
)
)
.then(testElementExists('.payment-confirmation'))
// Set password on passwordless account
.then(openVerificationLinkInSameTab(email, 0))
.then(fillOutFinishAccountSetup(PASSWORD))
.then(testElementExists('#splash-logo'))
.then(
clearBrowserState({
'123done': true,
force: true,
})
)
.then(openPage(ENTER_EMAIL_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
);
},
},
});

Просмотреть файл

@ -1,135 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const ENTER_EMAIL_URL = config.fxaContentRoot;
const SUPPORT_URL = config.fxaContentRoot + 'support';
const PASSWORD = 'amazingpassword';
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
openPage,
subscribeToTestProduct,
testUrlPathnameEquals,
testElementExists,
type,
typeNative,
} = FunctionalHelpers;
registerSuite('support form without valid session', {
tests: {
'go to support form, redirects to index': function () {
return this.remote
.then(clearBrowserState({ force: true }))
.then(openPage(SUPPORT_URL, selectors.ENTER_EMAIL.HEADER));
},
},
});
registerSuite('support form without active subscriptions', {
tests: {
'go to support form, redirects to subscription management, then back to settings': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(openPage(SUPPORT_URL, selectors.SETTINGS.SUB_PANELS))
.then(testUrlPathnameEquals('/settings'));
},
},
});
registerSuite('support form with an active subscription', {
tests: {
'go to support form, submits the form': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(subscribeToTestProduct())
.then(openPage(SUPPORT_URL, 'div.support'))
.then(click('#product_chosen a.chosen-single'))
.then(
click(
'#product_chosen ul.chosen-results li[data-option-array-index="1"]'
)
)
.then(click('#topic_chosen a.chosen-single'))
.then(
click(
'#topic_chosen ul.chosen-results li[data-option-array-index="1"]'
)
)
// This next bit rely on the product having at least one
// 'support:app:...' entry in its metadata
.then(click('#app_chosen a.chosen-single'))
.then(
click(
'#app_chosen ul.chosen-results li[data-option-array-index="1"]'
)
)
// test hitting enter and making sure we don't leave the form
.then(typeNative('input[name="subject"]', 'ENTER'))
.then(
type(
'textarea[name=message]',
'please send halp for functional tests'
)
)
);
// Since we don't have proper Zendesk config in CircleCI, the form
// cannot be successfully submitted.
// .then(click('button[type=submit]'))
// .then(testElementExists('.subscription-management'));
},
'go to support form, cancel, redirects to subscription management': function () {
if (
process.env.CIRCLECI === 'true' &&
!process.env.SUBHUB_STRIPE_APIKEY
) {
this.skip('missing Stripe API key in CircleCI run');
}
const email = createEmail();
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(clearBrowserState())
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.SETTINGS.HEADER))
.then(subscribeToTestProduct())
.then(openPage(SUPPORT_URL, 'div.support'))
.then(click('button.cancel', '.subscription-management'));
},
},
});

Просмотреть файл

@ -1,70 +0,0 @@
/* eslint-disable camelcase */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const FORCE_AUTH_PAGE_URL = `${config.fxaContentRoot}force_auth?context=fx_desktop_v1&service=sync`;
const SIGNIN_PAGE_URL = `${config.fxaContentRoot}signin?context=fx_desktop_v1&service=sync`;
const SIGNUP_PAGE_URL = `${config.fxaContentRoot}signin?context=fx_desktop_v1&service=sync`;
const RESET_PASSWORD_PAGE_URL = `${config.fxaContentRoot}reset_password?context=fx_desktop_v1&service=sync`;
const {
clearBrowserState,
click,
openPage,
testElementExists,
} = FunctionalHelpers;
registerSuite('Firefox Desktop Sync v1', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ force: true }));
},
afterEach: function () {
return this.remote.execute(() => {
// Opening about:blank aborts the Firefox download
// and prevents the tests from stalling when run on CentOS
window.location.href = 'about:blank';
});
},
tests: {
force_auth: function () {
return this.remote
.then(openPage(FORCE_AUTH_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
signin: function () {
return this.remote
.then(openPage(SIGNIN_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
signup: function () {
return this.remote
.then(openPage(SIGNUP_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
reset_password: function () {
return this.remote
.then(
openPage(RESET_PASSWORD_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER)
)
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
},
});

Просмотреть файл

@ -1,70 +0,0 @@
/* eslint-disable camelcase */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const FORCE_AUTH_PAGE_URL = `${config.fxaContentRoot}force_auth?context=fx_desktop_v2&service=sync`;
const SIGNIN_PAGE_URL = `${config.fxaContentRoot}signin?context=fx_desktop_v2&service=sync`;
const SIGNUP_PAGE_URL = `${config.fxaContentRoot}signin?context=fx_desktop_v2&service=sync`;
const RESET_PASSWORD_PAGE_URL = `${config.fxaContentRoot}reset_password?context=fx_desktop_v2&service=sync`;
const {
clearBrowserState,
click,
openPage,
testElementExists,
} = FunctionalHelpers;
registerSuite('Firefox Desktop Sync v2', {
beforeEach: function () {
return this.remote.then(clearBrowserState({ force: true }));
},
afterEach: function () {
return this.remote.execute(() => {
// Opening about:blank aborts the Firefox download
// and prevents the tests from stalling when run on CentOS
window.location.href = 'about:blank';
});
},
tests: {
force_auth: function () {
return this.remote
.then(openPage(FORCE_AUTH_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
signin: function () {
return this.remote
.then(openPage(SIGNIN_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
signup: function () {
return this.remote
.then(openPage(SIGNUP_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER))
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
reset_password: function () {
return this.remote
.then(
openPage(RESET_PASSWORD_PAGE_URL, selectors.UPDATE_FIREFOX.HEADER)
)
.then(click(selectors.UPDATE_FIREFOX.BUTTON_DOWNLOAD_FIREFOX))
.then(testElementExists(selectors.DOWNLOAD_FIREFOX_THANKS.HEADER));
},
},
});

Просмотреть файл

@ -1,373 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const QUERY_PARAMS = '?context=fx_desktop_v3&service=sync&action=email';
const INDEX_PAGE_URL = `${config.fxaContentRoot}${QUERY_PARAMS}`;
const SIGNUP_PAGE_URL = `${config.fxaContentRoot}signup${QUERY_PARAMS}`;
const SIGNIN_PAGE_URL = `${config.fxaContentRoot}signin${QUERY_PARAMS}`;
let email;
const PASSWORD = 'PASSWORD123123';
const PASSWORD_WITH_TYPO = 'PASSWORD1234';
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutSignUpCode,
fillOutSignInTokenCode,
noSuchElement,
openPage,
testElementExists,
testElementTextEquals,
testElementTextInclude,
testElementValueEquals,
testIsBrowserNotified,
type,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('Firefox Desktop Sync v3 email first', {
beforeEach() {
email = createEmail('sync{id}');
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'open directly to /signup page, refresh on the /signup page': function () {
return (
this.remote
// redirected immediately to the / page
.then(openPage(SIGNUP_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
.refresh()
// refresh sends the user back to the first step
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
);
},
'open directly to /signin page, refresh on the /signin page': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
// redirected immediately to the / page
.then(openPage(SIGNIN_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.refresh()
// refresh sends the user back to the first step
.then(testElementExists(selectors.ENTER_EMAIL.HEADER))
);
},
'enter a firefox.com address': function () {
return this.remote
.then(openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(visibleByQSA(selectors.ENTER_EMAIL.SYNC_DESCRIPTION))
.then(type(selectors.ENTER_EMAIL.EMAIL, 'testuser@firefox.com'))
.then(click(selectors.ENTER_EMAIL.SUBMIT))
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP))
.then(
testElementTextInclude(
selectors.ENTER_EMAIL.TOOLTIP,
'firefox.com does not offer email'
)
);
},
signup: function () {
return (
this.remote
.then(openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(visibleByQSA(selectors.ENTER_EMAIL.SYNC_DESCRIPTION))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
// user thinks they mistyped their email
.then(
click(
selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
// passwords do not match should cause an error
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(testElementExists(selectors.SIGNUP_PASSWORD.SHOW_PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD_WITH_TYPO))
.then(testElementExists(selectors.SIGNUP_PASSWORD.SHOW_VPASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.AGE, 21))
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.SIGNUP_PASSWORD.ERROR_PASSWORDS_DO_NOT_MATCH
)
)
.then(
testElementTextEquals(
selectors.SIGNUP_PASSWORD.TOOLTIP,
'Passwords do not match'
)
)
// fix the password mismatch
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.CHOOSE_WHAT_TO_SYNC.HEADER
)
)
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.SUBMIT))
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(fillOutSignUpCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
);
},
'COPPA disabled': function () {
return this.remote
.then(
openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
coppa: 'false',
},
})
)
.then(visibleByQSA(selectors.ENTER_EMAIL.SYNC_DESCRIPTION))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
)
.then(noSuchElement(selectors.SIGNUP_PASSWORD.AGE))
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.CHOOSE_WHAT_TO_SYNC.HEADER
)
);
},
'merge cancelled': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(visibleByQSA(selectors.ENTER_EMAIL.SYNC_DESCRIPTION))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(click(selectors.ENTER_EMAIL.SUBMIT, selectors.ENTER_EMAIL.ERROR))
.then(testIsBrowserNotified('fxaccounts:can_link_account'));
},
'email specified by relier, invalid': function () {
const invalidEmail = 'invalid@';
return this.remote
.then(
openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
email: invalidEmail,
},
})
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, invalidEmail))
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP))
.then(
testElementTextEquals(
selectors.ENTER_EMAIL.TOOLTIP,
'Valid email required'
)
);
},
'email specified by relier, empty string': function () {
const emptyEmail = '';
return this.remote
.then(
openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
email: emptyEmail,
},
})
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, emptyEmail))
.then(visibleByQSA(selectors.ENTER_EMAIL.TOOLTIP))
.then(
testElementTextEquals(
selectors.ENTER_EMAIL.TOOLTIP,
'Valid email required'
)
);
},
'email specified by relier, not registered': function () {
return (
this.remote
.then(
openPage(INDEX_PAGE_URL, selectors.SIGNUP_PASSWORD.HEADER, {
query: {
email,
},
})
)
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
// user realizes it's the wrong email address.
.then(
click(
selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
);
},
'email specified by relier, registered': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openPage(INDEX_PAGE_URL, selectors.SIGNIN_PASSWORD.HEADER, {
query: {
email,
},
})
)
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
// user realizes it's the wrong email address.
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
);
},
'email specified by relier, cancel merge': function () {
return this.remote
.then(
openPage(INDEX_PAGE_URL, selectors['400'].HEADER, {
query: {
email,
},
webChannelResponses: {
'fxaccounts:can_link_account': { ok: false },
},
})
)
.then(
testElementTextInclude(
selectors['400'].ERROR,
'Login attempt cancelled'
)
);
},
'cached credentials': function () {
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(INDEX_PAGE_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.SIGNIN_TOKEN_CODE.HEADER
)
)
.then(fillOutSignInTokenCode(email, 0))
// Use cached credentials form last time, but user must enter password
.then(openPage(INDEX_PAGE_URL, selectors.SIGNIN_PASSWORD.HEADER))
.then(testElementValueEquals(selectors.SIGNIN_PASSWORD.EMAIL, email))
// user wants to use a different email
.then(
click(
selectors.SIGNIN_PASSWORD.LINK_USE_DIFFERENT,
selectors.ENTER_EMAIL.HEADER
)
)
.then(testElementValueEquals(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNIN_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNIN_PASSWORD.PASSWORD, PASSWORD))
.then(
click(
selectors.SIGNIN_PASSWORD.SUBMIT,
selectors.SIGNIN_TOKEN_CODE.HEADER
)
)
);
},
},
});

Просмотреть файл

@ -1,299 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
let email;
const PASSWORD = 'password12345678';
const {
clearBrowserState,
click,
createEmail,
createUser,
createUID,
fillOutEmailFirstSignUp,
fillOutForceAuth,
fillOutSignInTokenCode,
fillOutSignInUnblock,
noSuchBrowserNotification,
noSuchElement,
openForceAuth,
testElementDisabled,
testElementExists,
testElementTextInclude,
testElementValueEquals,
testIsBrowserNotified,
visibleByQSA,
} = FunctionalHelpers;
registerSuite('Firefox Desktop Sync v3 force_auth', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'with a registered email, no uid': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(function (accountInfo) {
return openForceAuth({
query: {
context: 'fx_desktop_v3',
email,
forceUA: uaStrings['desktop_firefox_71'],
service: 'sync',
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
capabilities: null,
signedInUser: null,
},
},
}).call(this);
})
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(fillOutSignInTokenCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
'with a registered email, registered uid': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(function (accountInfo) {
return openForceAuth({
query: {
context: 'fx_desktop_v3',
email: email,
forceUA: uaStrings['desktop_firefox_71'],
service: 'sync',
uid: accountInfo.uid,
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
capabilities: null,
signedInUser: null,
},
},
}).call(this);
})
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(fillOutSignInTokenCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
'with a registered email, unregistered uid': function () {
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openForceAuth({
query: {
context: 'fx_desktop_v3',
email: email,
forceUA: uaStrings['desktop_firefox_71'],
service: 'sync',
uid: createUID(),
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
capabilities: null,
signedInUser: null,
},
},
})
)
.then(noSuchBrowserNotification('fxaccounts:logout'))
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(fillOutSignInTokenCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
'with an unregistered email, no uid': function () {
return (
this.remote
.then(
openForceAuth({
// user should be automatically redirected to the
// signup page where they can signup with the
// specified email
header: selectors.SIGNUP_PASSWORD.HEADER,
query: {
context: 'fx_desktop_v3',
email: email,
forceUA: uaStrings['desktop_firefox_71'],
service: 'sync',
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
capabilities: null,
signedInUser: null,
},
},
})
)
.then(visibleByQSA(selectors.SIGNUP_PASSWORD.ERROR))
.then(
testElementTextInclude(selectors.SIGNUP_PASSWORD.ERROR, 'recreate')
)
// ensure the email is filled in, and not editible.
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
.then(testElementDisabled(selectors.SIGNUP_PASSWORD.EMAIL))
.then(noSuchElement(selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT))
.then(fillOutEmailFirstSignUp(email, PASSWORD, { enterEmail: false }))
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.SUBMIT))
// the default behavior of not transitioning to the confirm
// screen is overridden because the user is signing up outside
// of about:accounts.
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(testIsBrowserNotified('fxaccounts:login'))
);
},
'with an unregistered email, registered uid': function () {
var unregisteredEmail = 'a' + email;
return (
this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(function (accountInfo) {
return openForceAuth({
// user should be automatically redirected to the
// signup page where they can signup with the
// specified email
header: selectors.SIGNUP_PASSWORD.HEADER,
query: {
context: 'fx_desktop_v3',
email: unregisteredEmail,
service: 'sync',
uid: accountInfo.uid,
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
capabilities: null,
signedInUser: null,
},
},
}).call(this);
})
.then(visibleByQSA(selectors.SIGNUP_PASSWORD.ERROR))
.then(
testElementTextInclude(selectors.SIGNUP_PASSWORD.ERROR, 'recreate')
)
// ensure the email is filled in, and not editible.
.then(
testElementValueEquals(
selectors.SIGNUP_PASSWORD.EMAIL,
unregisteredEmail
)
)
.then(testElementDisabled(selectors.SIGNUP_PASSWORD.EMAIL))
.then(noSuchElement(selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT))
);
},
'with an unregistered email, unregistered uid': function () {
return (
this.remote
.then(
openForceAuth({
// user should be automatically redirected to the
// signup page where they can signup with the
// specified email
header: selectors.SIGNUP_PASSWORD.HEADER,
query: {
context: 'fx_desktop_v3',
email: email,
service: 'sync',
uid: createUID(),
},
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
'fxaccounts:fxa_status': {
capabilities: null,
signedInUser: null,
},
},
})
)
.then(visibleByQSA(selectors.SIGNUP_PASSWORD.ERROR))
.then(
testElementTextInclude(selectors.SIGNUP_PASSWORD.ERROR, 'recreate')
)
// ensure the email is filled in, and not editible.
.then(testElementValueEquals(selectors.SIGNUP_PASSWORD.EMAIL, email))
.then(testElementDisabled(selectors.SIGNUP_PASSWORD.EMAIL))
.then(noSuchElement(selectors.SIGNUP_PASSWORD.LINK_USE_DIFFERENT))
);
},
'verified, blocked': function () {
email = createEmail('blocked{id}');
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openForceAuth({
query: {
context: 'fx_desktop_v3',
email: email,
service: 'sync',
uid: createUID(),
},
})
)
.then(noSuchBrowserNotification('fxaccounts:logout'))
.then(fillOutForceAuth(PASSWORD))
.then(testElementExists(selectors.SIGNIN_UNBLOCK.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(fillOutSignInUnblock(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
},
});

Просмотреть файл

@ -1,135 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
const config = intern._config;
const PASSWORD = 'passwordzxcv';
const RESET_PASSWORD_URL = `${config.fxaContentRoot}reset_password?context=fx_desktop_v3&service=sync`;
let email;
const {
clearBrowserState,
closeCurrentWindow,
createEmail,
createUser,
fillOutResetPassword,
fillOutCompleteResetPassword,
noSuchBrowserNotification,
openPage,
openVerificationLinkInNewTab,
switchToWindow,
testElementExists,
testIsBrowserNotified,
thenify,
type,
} = FunctionalHelpers;
const setupTest = thenify(function (query) {
return (
this.parent
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER, {
query,
})
)
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInNewTab(email, 0))
.then(switchToWindow(1))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(fillOutCompleteResetPassword(PASSWORD, PASSWORD))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.SUB_HEADER))
// the verification tab sends the WebChannel message. This fixes
// two problems: 1) initiating tab is closed, 2) The initiating
// tab when running in E10s does not have all the necessary data
// because localStorage is not shared.
.then(testIsBrowserNotified('fxaccounts:login'))
.then(closeCurrentWindow())
);
});
registerSuite('Firefox Desktop Sync v3 reset password', {
beforeEach: function () {
// timeout after 90 seconds
this.timeout = 90000;
email = createEmail();
return this.remote.then(clearBrowserState());
},
afterEach: function () {
// clear localStorage to avoid polluting other tests.
return this.remote.then(clearBrowserState());
},
tests: {
'reset password, verify same browser': function () {
const query = { forceUA: uaStrings['desktop_firefox_58'] };
return (
this.remote
.then(setupTest(query))
// In fx >= 58, about:accounts expects FxA to transition after email verification
.then(testElementExists(selectors.RESET_PASSWORD_COMPLETE.HEADER))
// Only expect the login message in the verification tab to avoid
// a race condition within the browser when it receives two login messages.
.then(noSuchBrowserNotification('fxaccounts:login'))
);
},
'reset password, verify same browser, password validation': function () {
const query = {
forceExperiment: 'passwordStrength',
forceExperimentGroup: 'designF',
};
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(openPage(RESET_PASSWORD_URL, selectors.RESET_PASSWORD.HEADER))
.then(fillOutResetPassword(email))
.then(testElementExists(selectors.CONFIRM_RESET_PASSWORD.HEADER))
.then(openVerificationLinkInNewTab(email, 0, { query }))
.then(switchToWindow(1))
.then(testElementExists(selectors.COMPLETE_RESET_PASSWORD.HEADER))
.then(type(selectors.COMPLETE_RESET_PASSWORD.PASSWORD, 'pass'))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD.PASSWORD_BALLOON.MIN_LENGTH_FAIL
)
)
.then(type(selectors.COMPLETE_RESET_PASSWORD.PASSWORD, 'password'))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD.PASSWORD_BALLOON.NOT_COMMON_FAIL
)
)
.then(type(selectors.COMPLETE_RESET_PASSWORD.PASSWORD, email))
.then(
testElementExists(
selectors.COMPLETE_RESET_PASSWORD.PASSWORD_BALLOON.NOT_EMAIL_FAIL
)
);
},
},
});

Просмотреть файл

@ -1,119 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const {
click,
clearBrowserState,
createEmail,
createUser,
fillOutChangePassword,
fillOutDeleteAccount,
fillOutEmailFirstSignIn,
fillOutSignInTokenCode,
noSuchBrowserNotification,
noSuchElement,
openPage,
testElementExists,
testIsBrowserNotified,
visibleByQSA,
} = FunctionalHelpers;
const config = intern._config;
const ENTER_EMAIL_URL =
config.fxaContentRoot + '?context=fx_desktop_v3&service=sync';
const SETTINGS_URL =
config.fxaContentRoot + 'settings?context=fx_desktop_v3&service=sync';
const SETTINGS_NOCONTEXT_URL = config.fxaContentRoot + 'settings';
const FIRST_PASSWORD = 'password';
const SECOND_PASSWORD = 'new_password';
let email;
registerSuite('Firefox Desktop Sync v3 settings', {
beforeEach: function () {
email = createEmail('sync{id}');
return (
this.remote
.then(createUser(email, FIRST_PASSWORD, { preVerified: true }))
.then(clearBrowserState())
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
webChannelResponses: {
'fxaccounts:can_link_account': {
ok: true,
},
},
})
)
.then(fillOutEmailFirstSignIn(email, FIRST_PASSWORD))
.then(testElementExists(selectors.SIGNIN_TOKEN_CODE.HEADER))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(fillOutSignInTokenCode(email, 0))
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
// wait until account data is in localstorage before redirecting
.then(
FunctionalHelpers.pollUntil(
function () {
const accounts = Object.keys(
JSON.parse(localStorage.getItem('__fxa_storage.accounts')) || {}
);
return accounts.length === 1 ? true : null;
},
[],
10000
)
)
.then(openPage(SETTINGS_URL, selectors.SETTINGS.HEADER))
);
},
tests: {
'sign in, change the password': function () {
return this.remote
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(visibleByQSA(selectors.CHANGE_PASSWORD.DETAILS))
.then(fillOutChangePassword(FIRST_PASSWORD, SECOND_PASSWORD));
},
'sign in, change the password by browsing directly to settings':
function () {
return this.remote
.then(openPage(SETTINGS_NOCONTEXT_URL, selectors.SETTINGS.HEADER))
.then(click(selectors.CHANGE_PASSWORD.MENU_BUTTON))
.then(visibleByQSA(selectors.CHANGE_PASSWORD.DETAILS))
.then(noSuchBrowserNotification('fxaccounts:change_password'))
.then(fillOutChangePassword(FIRST_PASSWORD, SECOND_PASSWORD));
},
'sign in, delete the account': function () {
return this.remote
.then(click(selectors.SETTINGS_DELETE_ACCOUNT.DELETE_ACCOUNT_BUTTON))
.then(visibleByQSA(selectors.SETTINGS_DELETE_ACCOUNT.DETAILS))
.then(fillOutDeleteAccount(FIRST_PASSWORD))
.then(testElementExists(selectors.ENTER_EMAIL.HEADER));
},
'sign in, no way to sign out': function () {
return (
this.remote
// make sure the sign out element doesn't exist
.then(noSuchElement(selectors.SETTINGS.SIGNOUT))
);
},
},
});

Просмотреть файл

@ -1,201 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
const config = intern._config;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync`;
let email;
const PASSWORD = '12345678';
const {
clearBrowserState,
click,
createEmail,
createUser,
fillOutEmailFirstSignIn,
fillOutSignInTokenCode,
fillOutSignInUnblock,
noEmailExpected,
openPage,
respondToWebChannelMessage,
testElementExists,
testEmailExpected,
testIsBrowserNotified,
thenify,
type,
visibleByQSA,
} = FunctionalHelpers;
const setupTest = thenify(function (options = {}) {
const signInEmail = options.signInEmail || email;
const signUpEmail = options.signUpEmail || email;
const successSelector = options.blocked
? selectors.SIGNIN_UNBLOCK.HEADER
: options.preVerified
? selectors.SIGNIN_TOKEN_CODE.HEADER
: selectors.CONFIRM_SIGNUP_CODE.HEADER;
const query = options.query || {
forceUA: uaStrings['desktop_firefox_58'],
};
return this.parent
.then(
createUser(signUpEmail, PASSWORD, { preVerified: options.preVerified })
)
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query,
})
)
.then(fillOutEmailFirstSignIn(signInEmail, PASSWORD))
.then(testElementExists(successSelector))
.then(testIsBrowserNotified('fxaccounts:can_link_account'));
});
registerSuite('Firefox Desktop Sync v3 signin', {
beforeEach: function () {
email = createEmail('sync{id}');
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'verified, does not need to confirm ': function () {
email = createEmail();
const query = {
forceUA: uaStrings['desktop_firefox_58'],
};
return this.remote
.then(createUser(email, PASSWORD, { preVerified: true }))
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query,
})
)
.then(fillOutEmailFirstSignIn(email, PASSWORD))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
verified: function () {
return this.remote
.then(setupTest({ preVerified: true }))
.then(fillOutSignInTokenCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
'verified, resend': function () {
return (
this.remote
.then(setupTest({ preVerified: true }))
.then(click(selectors.SIGNIN_TOKEN_CODE.LINK_RESEND))
.then(visibleByQSA(selectors.SIGNIN_TOKEN_CODE.SUCCESS))
// email 0 is the original signin email, open the resent email instead
.then(fillOutSignInTokenCode(email, 1))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
);
},
'verified - invalid code': function () {
return (
this.remote
.then(setupTest({ preVerified: true }))
// Displays invalid code errors
.then(type(selectors.SIGNIN_TOKEN_CODE.INPUT, 'INVALID'))
.then(click(selectors.SIGNIN_TOKEN_CODE.SUBMIT))
.then(visibleByQSA(selectors.SIGNIN_TOKEN_CODE.TOOLTIP))
.then(fillOutSignInTokenCode(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
);
},
unverified: function () {
// this test does a lot of waiting around, give it a little extra time
this.timeout = 60 * 1000;
return (
this.remote
.then(setupTest({ preVerified: false }))
// email 0 - initial sign up email
// email 1 - sign in w/ unverified address email
// email 2 - "You have verified your Firefox Account"
// there was a problem with 2 emails being sent on signin,
// ensure only one is sent. See #3890. Check for extra email
// must be done before opening the verification link,
// otherwise the "Account verified!" email is sent.
// maxAttempts is set to avoid intererence from
// the verification reminder emails. 5 attempts occur in 5 seconds,
// the first verification reminder is set after 10 seconds.
.then(noEmailExpected(email, 2, { maxAttempts: 5 }))
.then(fillOutSignInTokenCode(email, 1))
.then(testEmailExpected(email, 2))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
);
},
'verified, blocked': function () {
email = createEmail('blocked{id}');
return this.remote
.then(setupTest({ blocked: true, preVerified: true }))
.then(fillOutSignInUnblock(email, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'));
},
'verified, blocked, incorrect email case': function () {
const signUpEmail = createEmail('blocked{id}');
const signInEmail = signUpEmail.toUpperCase();
return (
this.remote
.then(
setupTest({
blocked: true,
preVerified: true,
signInEmail: signInEmail,
signUpEmail: signUpEmail,
})
)
// a second `can_link_account` request is sent to the browser after the
// unblock code is filled in, this time with the canonicalized email address.
// If a different user was signed in to the browser, two "merge" dialogs
// are presented, the first for the non-canonicalized email, the 2nd for
// the canonicalized email. Ugly UX, but at least the user can proceed.
.then(
respondToWebChannelMessage('fxaccounts:can_link_account', {
ok: true,
})
)
.then(fillOutSignInUnblock(signUpEmail, 0))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
.then(testIsBrowserNotified('fxaccounts:login'))
);
},
},
});

Просмотреть файл

@ -1,235 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const uaStrings = require('./lib/ua-strings');
const config = intern._config;
const ENTER_EMAIL_URL = `${config.fxaContentRoot}?context=fx_desktop_v3&service=sync`;
let email;
const PASSWORD = 'password12345678';
const {
clearBrowserState,
click,
createEmail,
fillOutEmailFirstSignUp,
fillOutSignUpCode,
noSuchElement,
noSuchBrowserNotification,
openPage,
testElementExists,
testIsBrowserNotified,
type,
} = FunctionalHelpers;
registerSuite('Firefox Desktop Sync v3 signup', {
beforeEach: function () {
email = createEmail();
return this.remote.then(clearBrowserState({ force: true }));
},
tests: {
'verify with signup code and CWTS': function () {
email = createEmail();
return (
this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: uaStrings['desktop_firefox_71'],
},
webChannelResponses: {
'fxaccounts:can_link_account': { ok: true },
'fxaccounts:fxa_status': {
signedInUser: null,
capabilities: {
multiService: true,
engines: ['history'],
},
},
},
})
)
.then(type(selectors.ENTER_EMAIL.EMAIL, email))
.then(
click(
selectors.ENTER_EMAIL.SUBMIT,
selectors.SIGNUP_PASSWORD.HEADER
)
)
.then(type(selectors.SIGNUP_PASSWORD.PASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.VPASSWORD, PASSWORD))
.then(type(selectors.SIGNUP_PASSWORD.AGE, '24'))
.then(
testElementExists(
selectors.SIGNUP_PASSWORD.CHOOSE_WHAT_TO_SYNC_HEADER
)
)
// check all the expected fields are there, and only the expected fields
.then(testElementExists(selectors.SIGNUP_PASSWORD.ENGINE_ADDONS))
.then(noSuchElement(selectors.SIGNUP_PASSWORD.ENGINE_ADDRESSES))
.then(testElementExists(selectors.SIGNUP_PASSWORD.ENGINE_BOOKMARKS))
.then(noSuchElement(selectors.SIGNUP_PASSWORD.ENGINE_CREDIT_CARDS))
.then(testElementExists(selectors.SIGNUP_PASSWORD.ENGINE_HISTORY))
.then(testElementExists(selectors.SIGNUP_PASSWORD.ENGINE_PASSWORDS))
.then(testElementExists(selectors.SIGNUP_PASSWORD.ENGINE_PREFS))
.then(testElementExists(selectors.SIGNUP_PASSWORD.ENGINE_TABS))
// uncheck the passwords and history engines
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_PASSWORDS))
.then(click(selectors.SIGNUP_PASSWORD.ENGINE_HISTORY))
.then(
click(
selectors.SIGNUP_PASSWORD.SUBMIT,
selectors.CONFIRM_SIGNUP_CODE.HEADER
)
)
.then(fillOutSignUpCode(email, 0))
// about:accounts does not take over, expect a screen transition.
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
);
},
'verify at CWTS': function () {
return (
this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: uaStrings['desktop_firefox_58'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
capabilities: {
// CWTS page only shown if multi-service is not enabled
multiService: false,
},
},
},
})
)
.then(noSuchElement(selectors.ENTER_EMAIL.LINK_SUGGEST_SYNC))
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// user should be transitioned to /choose_what_to_sync
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_ADDRESSES))
.then(
noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_CREDIT_CARDS)
)
.then(noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.DO_NOT_SYNC))
.then(testIsBrowserNotified('fxaccounts:can_link_account'))
.then(noSuchBrowserNotification('fxaccounts:login'))
.then(click(selectors.CHOOSE_WHAT_TO_SYNC.SUBMIT))
// user should be transitioned to the "go confirm your address" page
.then(testElementExists(selectors.CONFIRM_SIGNUP_CODE.HEADER))
.then(fillOutSignUpCode(email, 0))
// the login message is only sent after the sync preferences screen
// has been cleared.
.then(testIsBrowserNotified('fxaccounts:login'))
.then(testElementExists(selectors.CONNECT_ANOTHER_DEVICE.HEADER))
);
},
'engines not supported': function () {
return (
this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: uaStrings['desktop_firefox_58'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
signedInUser: null,
},
},
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// user should be transitioned to /choose_what_to_sync
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_ADDRESSES))
.then(
noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_CREDIT_CARDS)
)
);
},
'neither `creditcards` nor `addresses` supported': function () {
return (
this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: uaStrings['desktop_firefox_58'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
capabilities: {
engines: [],
},
signedInUser: null,
},
},
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// user should be transitioned to /choose_what_to_sync
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_ADDRESSES))
.then(
noSuchElement(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_CREDIT_CARDS)
)
);
},
'`creditcards` and `addresses` supported': function () {
return (
this.remote
.then(
openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER, {
query: {
forceUA: uaStrings['desktop_firefox_58'],
},
webChannelResponses: {
'fxaccounts:fxa_status': {
capabilities: {
engines: ['creditcards', 'addresses'],
},
signedInUser: null,
},
},
})
)
.then(fillOutEmailFirstSignUp(email, PASSWORD))
// user should be transitioned to /choose_what_to_sync
.then(testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.HEADER))
.then(
testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_ADDRESSES)
)
.then(
testElementExists(selectors.CHOOSE_WHAT_TO_SYNC.ENGINE_CREDIT_CARDS)
)
);
},
},
});

Просмотреть файл

@ -1,33 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const ENTER_EMAIL_URL = intern._config.fxaContentRoot;
const { click, createEmail, openPage, type } = FunctionalHelpers;
registerSuite('terms of service', {
beforeEach: function () {
return this.remote.then(FunctionalHelpers.clearBrowserState());
},
tests: {
'from signup': function () {
return this.remote
.then(openPage(ENTER_EMAIL_URL, selectors.ENTER_EMAIL.HEADER))
.then(type(selectors.ENTER_EMAIL.EMAIL, createEmail()))
.then(
click(selectors.ENTER_EMAIL.SUBMIT, selectors.SIGNUP_PASSWORD.HEADER)
)
.then(click(selectors.SIGNUP_PASSWORD.TOS, selectors.TOS.HEADER))
.then(click(selectors.TOS.LINK_BACK, selectors.SIGNUP_PASSWORD.HEADER));
},
},
});

Просмотреть файл

@ -1,147 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
const { registerSuite } = intern.getInterface('object');
const Constants = require('../../app/scripts/lib/constants');
const FunctionalHelpers = require('./lib/helpers');
const selectors = require('./lib/selectors');
const config = intern._config;
const CONFIRM_EMAIL_ROOT = config.fxaContentRoot + 'verify_email';
const PASSWORD = 'passwordcxzv';
let email;
let accountData;
let code;
let uid;
const {
createEmail,
createRandomHexString,
createUser,
getVerificationLink,
noSuchElement,
openPage,
sendVerificationReminders,
} = FunctionalHelpers;
registerSuite('verification reminders', {
beforeEach: function () {
email = createEmail();
return (
this.remote
.then(
createUser(email, PASSWORD, {
preVerified: false,
verificationMethod: 'email-otp',
})
)
.then(function (result) {
accountData = result;
uid = accountData.uid;
})
// The first email is a code, we need to wait for verification
// reminders which contain a link.
.then(sendVerificationReminders())
.then(getVerificationLink(email, 1))
.then(function (link) {
code = link.match(/code=([A-Za-z0-9]+)/)[1];
})
);
},
tests: {
'open verification link with malformed code': function () {
const code = createRandomHexString(Constants.CODE_LENGTH - 1);
const uid = accountData.uid;
const url = CONFIRM_EMAIL_ROOT + '?uid=' + uid + '&code=' + code;
return this.remote
.then(
openPage(url, selectors.COMPLETE_SIGNUP.VERIFICATION_LINK_DAMAGED)
)
.then(
noSuchElement(selectors.COMPLETE_SIGNUP.VERIFICATION_LINK_EXPIRED)
);
},
'open verification link with server reported bad code': function () {
const code = createRandomHexString(Constants.CODE_LENGTH);
const uid = accountData.uid;
const url = CONFIRM_EMAIL_ROOT + '?uid=' + uid + '&code=' + code;
return this.remote.then(
openPage(url, selectors.COMPLETE_SIGNUP.VERIFICATION_LINK_DAMAGED)
);
},
'open verification link with malformed uid': function () {
const uid = createRandomHexString(Constants.UID_LENGTH - 1);
const url = CONFIRM_EMAIL_ROOT + '?uid=' + uid + '&code=' + code;
return this.remote.then(
openPage(url, selectors.COMPLETE_SIGNUP.VERIFICATION_LINK_DAMAGED)
);
},
'open verification link with server reported bad uid': function () {
const uid = createRandomHexString(Constants.UID_LENGTH);
const url = CONFIRM_EMAIL_ROOT + '?uid=' + uid + '&code=' + code;
return this.remote.then(
openPage(url, selectors.COMPLETE_SIGNUP.VERIFICATION_LINK_EXPIRED)
);
},
'open valid email verification link': function () {
const url = CONFIRM_EMAIL_ROOT + '?uid=' + uid + '&code=' + code;
return this.remote.then(openPage(url, selectors.SIGNUP_COMPLETE.HEADER));
},
},
});
registerSuite('verification reminders - re-sign up after reminders are sent', {
beforeEach: function () {
email = createEmail();
return (
this.remote
.then(
createUser(email, PASSWORD, {
preVerified: false,
verificationMethod: 'email-otp',
})
)
.then(function (result) {
accountData = result;
uid = accountData.uid;
})
// The first email is a code, we need to wait for verification
// reminders which contain a link.
.then(sendVerificationReminders())
.then(getVerificationLink(email, 1))
.then(function (link) {
code = link.match(/code=([A-Za-z0-9]+)/)[1];
})
// re-sign up the same user with a different password, should expire
// the original verification link.
.then(createUser(email, 'secondpassword', { preVerified: false }))
);
},
tests: {
'open expired email verification link': function () {
const url = CONFIRM_EMAIL_ROOT + '?uid=' + uid + '&code=' + code;
return this.remote
.then(
openPage(url, selectors.COMPLETE_SIGNUP.VERIFICATION_LINK_EXPIRED)
)
.then(noSuchElement(selectors.COMPLETE_SIGNUP.LINK_RESEND));
},
},
});

Просмотреть файл

@ -1,39 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Select which tests to run on circleci.
*
* If CIRCLE_NODE_TOTAL and CIRCLE_NODE_INDEX environment vars are defined,
* tests are parallelized into CIRCLE_NODE_TOTAL runners. The suites are not
* exactly the same size and will take a different amount of time to run,
* but this is a good place to start.
*/
function selectCircleTests(allTests, groupsCount, groupNum) {
var testsToRun = allTests;
if (process.env.CIRCLE_NODE_TOTAL) {
console.log('CIRCLE_NODE_INDEX', process.env.CIRCLE_NODE_INDEX);
console.log('CIRCLE_NODE_TOTAL', process.env.CIRCLE_NODE_TOTAL);
var circleTotal = parseInt(process.env.CIRCLE_NODE_TOTAL, 10);
var circleIndex = parseInt(process.env.CIRCLE_NODE_INDEX, 10);
testsToRun = allTests.filter((test, index) => {
var passes = index % circleTotal === circleIndex;
return passes;
});
}
if (groupsCount && groupNum) {
testsToRun = testsToRun.slice(
Math.floor(((groupNum - 1) / groupsCount) * testsToRun.length),
Math.floor((groupNum / groupsCount) * testsToRun.length)
);
}
return testsToRun;
}
module.exports = selectCircleTests;

Просмотреть файл

@ -1,7 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//Disabling the suite as the tests are being flaky,
//We will revisit this later, ticket created https://mozilla-hub.atlassian.net/browse/FXA-6558
//module.exports = ['tests/functional/pairing.js'];

Просмотреть файл

@ -1,212 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const fs = require('fs');
const intern = require('intern').default;
const args = require('yargs').argv;
const firefoxProfile = require('./tools/firefox_profile');
// Tests
const testsMain = require('./functional');
const testsCircleCi = require('./functional_circle')(
testsMain,
args.groupsCount,
args.groupNum
);
const testsFunctionalSmoke = require('./functional_smoke');
const testsFunctionalRegression = require('./functional_regression');
const testsPairing = require('./functional_pairing');
const testsServer = require('./tests_server');
const testsServerResources = require('./tests_server_resources');
const testsSettings = require('./functional_settings');
const fxaAuthRoot = args.fxaAuthRoot || 'http://localhost:9000/v1';
const fxaContentRoot = args.fxaContentRoot || 'http://localhost:3030/';
const fxaOAuthRoot = args.fxaOAuthRoot || 'http://localhost:9000';
const fxaProfileRoot = args.fxaProfileRoot || 'http://localhost:1111';
const fxaTokenRoot = args.fxaTokenRoot || 'http://localhost:5000/token';
const fxaEmailRoot = args.fxaEmailRoot || 'http://localhost:9001';
const fxaOAuthApp = args.fxaOAuthApp || 'http://localhost:8080/';
const fxaUntrustedOauthApp =
args.fxaUntrustedOauthApp || 'http://localhost:10139/';
const fxaPaymentsRoot = args.fxaPaymentsRoot || 'http://localhost:3031/';
const output = args.output || 'test-results.xml';
const fxaSettingsV2Root = args.fxaSettingsV2Root || `${fxaContentRoot}settings`;
// "fxaProduction" is a little overloaded in how it is used in the tests.
// Sometimes it means real "stage" or real production configuration, but
// sometimes it also means fxa-dev style boxes like "latest". Configuration
// parameter "fxaDevBox" can be used as a crude way to distinguish between
// two.
const fxaProduction = !!args.fxaProduction;
const fxaDevBox = !!args.fxaDevBox;
const fxaToken = args.fxaToken || 'http://';
const asyncTimeout = parseInt(args.asyncTimeout || 10000, 10);
// On Circle, we bail after the first failure.
// args.bailAfterFirstFailure comes in as a string.
const bailAfterFirstFailure = args.bailAfterFirstFailure === 'true';
const testProductId = args.testProductId || 'prod_GqM9ToKK62qjkK';
const testPlanId = args.testPlanId || 'plan_GqM9N6qyhvxaVk';
// Intern specific options are here: https://theintern.io/docs.html#Intern/4/docs/docs%2Fconfiguration.md/properties
const config = {
asyncTimeout: asyncTimeout,
bail: bailAfterFirstFailure,
defaultTimeout: 45000, // 30 seconds just isn't long enough for some tests.
environments: {
browserName: 'firefox',
fixSessionCapabilities: 'no-detect',
usesHandleParameter: true,
},
filterErrorStack: true,
functionalSuites: testsMain,
fxaAuthRoot: fxaAuthRoot,
fxaContentRoot: fxaContentRoot,
fxaSettingsV2Root: fxaSettingsV2Root,
fxaDevBox: fxaDevBox,
fxaEmailRoot: fxaEmailRoot,
fxaOAuthApp: fxaOAuthApp,
fxaOAuthRoot: fxaOAuthRoot,
fxaProduction: fxaProduction,
fxaProfileRoot: fxaProfileRoot,
fxaToken: fxaToken,
fxaTokenRoot: fxaTokenRoot,
fxaUntrustedOauthApp: fxaUntrustedOauthApp,
fxaPaymentsRoot,
pageLoadTimeout: 30000,
reporters: [
{
name: 'junit',
options: {
filename: output,
},
},
'runner',
],
serverPort: 9091,
serverUrl: 'http://localhost:9091',
socketPort: 9077,
tunnelOptions: {
drivers: [
{
name: 'firefox',
},
],
},
testProductId,
testPlanId,
};
if (args.grep) {
config.grep = new RegExp(args.grep, 'i');
}
if (args.suites) {
switch (args.suites) {
case 'pairing':
config.functionalSuites = testsPairing;
config.isTestingPairing = true;
break;
case 'functional_smoke':
config.functionalSuites = testsFunctionalSmoke;
break;
case 'functional_regression':
config.functionalSuites = testsFunctionalRegression;
break;
case 'settings':
config.functionalSuites = testsSettings;
break;
case 'all':
config.functionalSuites = testsMain;
break;
case 'circle':
config.functionalSuites = testsCircleCi;
console.log('Running tests:', config.functionalSuites);
break;
case 'server':
case 'server-resources':
config.functionalSuites = [];
config.node = {
suites: testsServer,
};
config.tunnelOptions = {};
config.environments = {
browserName: 'node',
};
config.reporters = 'pretty';
if (args.suites === 'server-resources') {
config.node.suites = testsServerResources;
}
break;
}
}
if (args.unit) {
config.functionalSuites.unshift('tests/functional/mocha.js');
}
if (args.groups !== undefined && args.groupIndex !== undefined) {
const index = args.groupIndex;
const groups = args.groups;
const groupSize = Math.ceil(config.functionalSuites.length / groups);
const originalSuiteSize = config.functionalSuites.length;
const targeted = config.functionalSuites.splice(groupSize * index, groupSize);
console.log(`Running group ${args.groupIndex + 1} of ${args.groups}.`);
console.log(
`Running ${targeted.length} of ${originalSuiteSize} tests suites.`
);
// Target a 'block' of tests to run
config.functionalSuites = targeted;
}
config.capabilities = {};
config.capabilities['moz:firefoxOptions'] = {};
// to create a profile, give it the `config` option.
config.capabilities['moz:firefoxOptions'].profile = firefoxProfile(config); //eslint-disable-line camelcase
// uncomment to show devtools on launch
// config.capabilities['moz:firefoxOptions'].args = ['-devtools'];
// custom Firefox binary location, if specified then the default is ignored.
// ref: https://code.google.com/p/selenium/wiki/DesiredCapabilities#WebDriver
if (args.firefoxBinary) {
config.capabilities['moz:firefoxOptions'].binary = args.firefoxBinary; //eslint-disable-line camelcase
}
const failed = [];
intern.on('suiteEnd', (test) => {
if (test.error) {
failed.push(test);
}
});
intern.on('testEnd', (test) => {
if (test.error) {
failed.push(test);
}
});
intern.on('afterRun', () => {
if (failed.length) {
// This text output is used later to target tests to rerun. The value
// is essentially just a big regex. Note that that the postfixed $
// helps the regex be more precisely.
fs.writeFileSync('rerun.txt', failed.map((f) => `${f.name}$`).join('|'));
}
});
intern.configure(config);
intern.run().catch((e) => {
// This might not throw, BUG filed: https://github.com/theintern/intern/issues/868
console.log(e);
process.exit(1);
});

Просмотреть файл

@ -4,8 +4,7 @@
const request = require('./request');
const config = intern._config;
const EMAIL_SERVER_ROOT = config.fxaEmailRoot;
const EMAIL_SERVER_ROOT = 'http://localhost:9001';
/**
* Wait for an email.