зеркало из https://github.com/mozilla/fxa.git
fix(tests): Add some tweaks to reduce flaky playwright tests
This commit is contained in:
Родитель
503f99ea76
Коммит
6e45010bc4
|
@ -651,7 +651,7 @@ jobs:
|
|||
default: large
|
||||
parallelism:
|
||||
type: integer
|
||||
default: 8
|
||||
default: 4
|
||||
executor: functional-test-executor
|
||||
resource_class: << parameters.resource_class >>
|
||||
parallelism: << parameters.parallelism >>
|
||||
|
|
|
@ -282,7 +282,7 @@ export class LoginPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async getTooltipError() {
|
||||
return this.page.innerText(selectors.TOOLTIP);
|
||||
return this.page.locator(selectors.TOOLTIP).innerText();
|
||||
}
|
||||
|
||||
async unblock(email: string) {
|
||||
|
@ -296,17 +296,14 @@ export class LoginPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async submit() {
|
||||
return Promise.all([
|
||||
this.page.locator(selectors.SUBMIT).click(),
|
||||
this.page.waitForNavigation({ waitUntil: 'load' }),
|
||||
]);
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page.locator(selectors.SUBMIT).click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
|
||||
async clickForgotPassword() {
|
||||
return Promise.all([
|
||||
this.page.locator(selectors.LINK_RESET_PASSWORD).click(),
|
||||
this.page.waitForNavigation({ waitUntil: 'networkidle' }),
|
||||
]);
|
||||
await this.page.locator(selectors.LINK_RESET_PASSWORD).click();
|
||||
await this.page.waitForURL(/reset_password/);
|
||||
}
|
||||
|
||||
async isSigninHeader() {
|
||||
|
@ -360,10 +357,8 @@ export class LoginPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async clickDontHaveRecoveryKey() {
|
||||
return Promise.all([
|
||||
this.page.locator(selectors.LINK_LOST_RECOVERY_KEY).click(),
|
||||
this.page.waitForNavigation(),
|
||||
]);
|
||||
await this.page.locator(selectors.LINK_LOST_RECOVERY_KEY).click();
|
||||
await this.page.waitForURL(/complete_reset_password/);
|
||||
}
|
||||
|
||||
setRecoveryKey(key: string) {
|
||||
|
@ -375,19 +370,19 @@ export class LoginPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async setNewPassword(password: string) {
|
||||
await this.page.fill(selectors.PASSWORD, password);
|
||||
await this.page.fill(selectors.VPASSWORD, password);
|
||||
await this.page.locator(selectors.PASSWORD).fill(password);
|
||||
await this.page.locator(selectors.VPASSWORD).fill(password);
|
||||
await this.submit();
|
||||
}
|
||||
|
||||
async setTotp(secret: string) {
|
||||
const code = await getCode(secret);
|
||||
await this.page.fill(selectors.NUMBER_INPUT, code);
|
||||
await this.page.locator(selectors.NUMBER_INPUT).fill(code);
|
||||
await this.submit();
|
||||
}
|
||||
|
||||
async getPrefilledEmail() {
|
||||
return this.page.innerText(selectors.EMAIL_PREFILLED);
|
||||
return this.page.locator(selectors.EMAIL_PREFILLED).innerText();
|
||||
}
|
||||
|
||||
async getEmailInputElement() {
|
||||
|
@ -395,11 +390,11 @@ export class LoginPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async getEmailInput() {
|
||||
return this.page.inputValue(selectors.EMAIL);
|
||||
return this.page.locator(selectors.EMAIL).inputValue();
|
||||
}
|
||||
|
||||
async getPasswordInput() {
|
||||
return this.page.inputValue(selectors.PASSWORD);
|
||||
return this.page.locator(selectors.PASSWORD).inputValue();
|
||||
}
|
||||
|
||||
async isCachedLogin() {
|
||||
|
@ -416,7 +411,7 @@ export class LoginPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async getErrorMessage() {
|
||||
return this.page.innerText(selectors.ERROR);
|
||||
return this.page.locator(selectors.ERROR).innerText();
|
||||
}
|
||||
|
||||
createEmail(template?: string) {
|
||||
|
|
|
@ -38,10 +38,11 @@ export class SubscribePage extends BaseLayout {
|
|||
'[data-testid="paypal-button-container"]'
|
||||
);
|
||||
await paypalButton.waitFor({ state: 'visible' });
|
||||
const [paypalWindow] = await Promise.all([
|
||||
this.page.waitForEvent('popup'),
|
||||
this.page.locator('[data-testid="paypal-button-container"]').click(),
|
||||
]);
|
||||
|
||||
const paypalWindowPromise = this.page.waitForEvent('popup');
|
||||
await this.page.locator('[data-testid="paypal-button-container"]').click();
|
||||
const paypalWindow = await paypalWindowPromise;
|
||||
|
||||
await paypalWindow.waitForLoadState('load');
|
||||
await paypalWindow.waitForNavigation({
|
||||
url: /checkoutnow/,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { BaseLayout } from './layout';
|
||||
import { selectors } from './login';
|
||||
|
||||
export class RelierPage extends BaseLayout {
|
||||
goto(query?: string) {
|
||||
|
@ -27,25 +28,22 @@ export class RelierPage extends BaseLayout {
|
|||
]);
|
||||
}
|
||||
|
||||
clickEmailFirst() {
|
||||
return Promise.all([
|
||||
this.page.locator('button.email-first-button').click(),
|
||||
this.page.waitForNavigation(),
|
||||
]);
|
||||
async clickEmailFirst() {
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page.locator('button.email-first-button').click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
|
||||
clickSignIn() {
|
||||
return Promise.all([
|
||||
this.page.locator('button.sign-in-button.signin').click(),
|
||||
this.page.waitForNavigation(),
|
||||
]);
|
||||
async clickSignIn() {
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page.locator('button.sign-in-button.signin').click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
|
||||
clickForceAuth() {
|
||||
return Promise.all([
|
||||
this.page.locator('button.force-auth').click(),
|
||||
this.page.waitForNavigation(),
|
||||
]);
|
||||
async clickForceAuth() {
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page.locator('button.force-auth').click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
|
||||
clickChooseFlow() {
|
||||
|
@ -53,27 +51,26 @@ export class RelierPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async clickSubscribe() {
|
||||
await Promise.all([
|
||||
this.page.getByRole('link', { name: 'Subscribe to Pro (USD)' }).click(),
|
||||
this.page.waitForNavigation({ waitUntil: 'load' }),
|
||||
]);
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page
|
||||
.getByRole('link', { name: 'Subscribe to Pro (USD)' })
|
||||
.click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
|
||||
async clickSubscribe6Month() {
|
||||
await Promise.all([
|
||||
this.page
|
||||
.getByRole('link', { name: 'Subscribe to Pro 6m (USD)' })
|
||||
.click(),
|
||||
this.page.waitForNavigation({ waitUntil: 'load' }),
|
||||
]);
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page
|
||||
.getByRole('link', { name: 'Subscribe to Pro 6m (USD)' })
|
||||
.click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
|
||||
async clickSubscribe12Month() {
|
||||
await Promise.all([
|
||||
this.page
|
||||
.getByRole('link', { name: 'Subscribe to Pro 12m (USD)' })
|
||||
.click(),
|
||||
this.page.waitForNavigation({ waitUntil: 'load' }),
|
||||
]);
|
||||
const waitForNavigation = this.page.waitForNavigation();
|
||||
await this.page
|
||||
.getByRole('link', { name: 'Subscribe to Pro 12m (USD)' })
|
||||
.click();
|
||||
return waitForNavigation;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ export class ResetPasswordPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async resetNewPassword(password: string) {
|
||||
await this.page.fill(selectors.PASSWORD, password);
|
||||
await this.page.fill(selectors.VPASSWORD, password);
|
||||
await this.page.locator(selectors.PASSWORD).fill(password);
|
||||
await this.page.locator(selectors.VPASSWORD).fill(password);
|
||||
await this.page.locator(selectors.SUBMIT).click();
|
||||
}
|
||||
|
||||
|
|
|
@ -62,9 +62,8 @@ export abstract class SettingsLayout extends BaseLayout {
|
|||
|
||||
async signOut() {
|
||||
await this.clickAvatarIcon();
|
||||
await Promise.all([
|
||||
this.clickSignOut(),
|
||||
this.page.waitForURL(this.target.baseUrl, { waitUntil: 'load' }),
|
||||
]);
|
||||
const waitForURL = this.page.waitForURL(this.target.baseUrl);
|
||||
await this.clickSignOut();
|
||||
return waitForURL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,19 +13,19 @@ export class RecoveryKeyPage extends SettingsLayout {
|
|||
}
|
||||
|
||||
async invalidRecoveryKeyError() {
|
||||
return this.page.innerText('#error-tooltip-159');
|
||||
return this.page.locator('#error-tooltip-159').innerText();
|
||||
}
|
||||
|
||||
setPassword(password: string) {
|
||||
return this.page.fill('input[type=password]', password);
|
||||
return this.page.locator('input[type=password]').fill(password);
|
||||
}
|
||||
|
||||
async confirmRecoveryKey() {
|
||||
return this.page.click('button[type=submit]');
|
||||
return this.page.locator('button[type=submit]').click();
|
||||
}
|
||||
|
||||
async clickLostRecoveryKey() {
|
||||
return this.page.click('.lost-recovery-key');
|
||||
return this.page.locator('.lost-recovery-key').click();
|
||||
}
|
||||
|
||||
submit() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PlaywrightTestConfig, Project } from '@playwright/test';
|
||||
import path from 'path';
|
||||
import * as path from 'path';
|
||||
import { TargetNames } from './lib/targets';
|
||||
import { TestOptions, WorkerOptions } from './lib/fixtures/standard';
|
||||
import { getFirefoxUserPrefs } from './lib/targets/firefoxUserPrefs';
|
||||
|
@ -11,10 +11,20 @@ const CI = !!process.env.CI;
|
|||
const DEBUG = !!process.env.DEBUG;
|
||||
const SLOWMO = parseInt(process.env.PLAYWRIGHT_SLOWMO || '0');
|
||||
|
||||
let retries = 0,
|
||||
workers = undefined,
|
||||
maxFailures = 0;
|
||||
if (CI) {
|
||||
// Overall maxFailures is now dependent on the number of retries, workers
|
||||
retries = 3;
|
||||
workers = 2;
|
||||
maxFailures = retries * workers * 2;
|
||||
}
|
||||
|
||||
const config: PlaywrightTestConfig<TestOptions, WorkerOptions> = {
|
||||
outputDir: path.resolve(__dirname, '../../artifacts/functional'),
|
||||
forbidOnly: CI,
|
||||
retries: CI ? 2 : 0,
|
||||
retries,
|
||||
testDir: 'tests',
|
||||
use: {
|
||||
viewport: { width: 1280, height: 720 },
|
||||
|
@ -66,8 +76,8 @@ const config: PlaywrightTestConfig<TestOptions, WorkerOptions> = {
|
|||
],
|
||||
]
|
||||
: 'list',
|
||||
workers: CI ? 2 : undefined,
|
||||
maxFailures: CI ? 3 : 0,
|
||||
workers,
|
||||
maxFailures,
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
@ -4,5 +4,5 @@ DIR=$(dirname "$0")
|
|||
|
||||
cd "$DIR/../../../"
|
||||
|
||||
circleci tests glob "packages/functional-tests/tests/**/*.spec.ts" | circleci tests split --split-by=timings > tests-to-run.txt
|
||||
circleci tests glob "packages/functional-tests/tests/**/*.spec.ts" | circleci tests split > tests-to-run.txt
|
||||
yarn workspace functional-tests test $(cat tests-to-run.txt|awk -F"/" '{ print $NF }')
|
||||
|
|
|
@ -9,7 +9,7 @@ test.describe('OAuth force auth', () => {
|
|||
await relier.clickForceAuth();
|
||||
|
||||
// Email is prefilled
|
||||
await expect(await login.page.innerText('#prefillEmail')).toMatch(
|
||||
await expect(await login.page.innerText('#prefillEmail')).toContain(
|
||||
credentials.email
|
||||
);
|
||||
await login.setPassword(credentials.password);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import { test, expect } from '../../lib/fixtures/standard';
|
||||
|
||||
test.describe('OAuth totp', () => {
|
||||
test.beforeEach(async ({}, { project }) => {
|
||||
test.slow();
|
||||
});
|
||||
|
||||
test('can add TOTP to account and confirm oauth signin', async ({
|
||||
credentials,
|
||||
pages: { login, relier, settings, totp },
|
||||
|
|
|
@ -14,23 +14,19 @@ const NEW_PASSWORD = 'notYourAveragePassW0Rd';
|
|||
|
||||
test.describe('reset password', () => {
|
||||
test.beforeEach(async ({}, { project }) => {
|
||||
test.slow(project.name !== 'local', 'email delivery can be slow');
|
||||
test.slow();
|
||||
});
|
||||
|
||||
test.skip('can reset password', async ({
|
||||
page,
|
||||
target,
|
||||
credentials,
|
||||
context,
|
||||
}) => {
|
||||
test('can reset password', async ({ page, target, credentials, context }) => {
|
||||
await page.goto(getReactFeatureFlagUrl(target, '/reset_password'));
|
||||
|
||||
// Verify react page has been loaded
|
||||
await page.waitForSelector('#root');
|
||||
|
||||
await page.locator('input').fill(credentials.email);
|
||||
let waitForNavigation = page.waitForNavigation();
|
||||
await page.locator('text="Begin reset"').click();
|
||||
await page.waitForNavigation();
|
||||
await waitForNavigation;
|
||||
|
||||
// Verify confirm password reset page elements
|
||||
expect(
|
||||
|
@ -71,34 +67,33 @@ test.describe('reset password', () => {
|
|||
await diffPage.locator('input[name="newPassword"]').fill(NEW_PASSWORD);
|
||||
await diffPage.locator('input[name="confirmPassword"]').fill(NEW_PASSWORD);
|
||||
|
||||
await Promise.all([
|
||||
await diffPage.locator('text="Reset password"').click(),
|
||||
await diffPage.waitForNavigation(),
|
||||
]);
|
||||
const pageWaitForNavigation = page.waitForNavigation();
|
||||
const diffPageWaitForNavigation = diffPage.waitForNavigation();
|
||||
await diffPage.locator('text="Reset password"').click();
|
||||
await diffPageWaitForNavigation;
|
||||
await pageWaitForNavigation;
|
||||
|
||||
expect(
|
||||
await diffPage.locator('text="Your password has been reset"').isEnabled()
|
||||
).toBeTruthy();
|
||||
|
||||
await diffPage.close();
|
||||
|
||||
// Attempt to login
|
||||
await page.waitForNavigation();
|
||||
expect(
|
||||
await page.locator('text="Enter your email"').isEnabled()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('input[type=email]').fill(credentials.email);
|
||||
await Promise.all([
|
||||
await page.locator('text="Sign up or sign in"').click(),
|
||||
await page.waitForNavigation(),
|
||||
]);
|
||||
|
||||
waitForNavigation = page.waitForNavigation();
|
||||
await page.locator('text="Sign up or sign in"').click();
|
||||
await waitForNavigation;
|
||||
|
||||
await page.locator('#password').fill(NEW_PASSWORD);
|
||||
|
||||
await Promise.all([
|
||||
await page.locator('text="Sign in"').click(),
|
||||
await page.waitForNavigation(),
|
||||
]);
|
||||
waitForNavigation = page.waitForNavigation();
|
||||
await page.locator('text="Sign in"').click();
|
||||
await waitForNavigation;
|
||||
|
||||
const settingsHeader = await page.locator('text=Settings');
|
||||
expect(await settingsHeader.isEnabled()).toBeTruthy();
|
||||
|
|
|
@ -22,7 +22,7 @@ test.describe('severity-1 #smoke', () => {
|
|||
);
|
||||
await page.goto(link, { waitUntil: 'networkidle' });
|
||||
await login.setNewPassword(credentials.password);
|
||||
expect(page.url()).toMatch(settings.url);
|
||||
expect(page.url()).toContain(settings.url);
|
||||
});
|
||||
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293431
|
||||
|
|
|
@ -9,7 +9,7 @@ test.describe('recovery key test', () => {
|
|||
async ({ credentials, page, pages: { settings, recoveryKey } }) => {
|
||||
// Generating and consuming recovery keys is a slow process
|
||||
test.slow();
|
||||
|
||||
|
||||
await settings.goto();
|
||||
let status = await settings.recoveryKey.statusText();
|
||||
expect(status).toEqual('Not Set');
|
||||
|
@ -43,8 +43,6 @@ test.describe('recovery key test', () => {
|
|||
page,
|
||||
pages: { settings, recoveryKey, login },
|
||||
}) => {
|
||||
// Generating and consuming recovery keys is a slow process
|
||||
test.slow();
|
||||
let secondKey;
|
||||
|
||||
// Create new recovery key
|
||||
|
@ -76,7 +74,9 @@ test.describe('recovery key test', () => {
|
|||
await recoveryKey.confirmRecoveryKey();
|
||||
|
||||
// Verify the error
|
||||
expect(await recoveryKey.invalidRecoveryKeyError()).toContain('Invalid account recovery key');
|
||||
expect(await recoveryKey.invalidRecoveryKeyError()).toContain(
|
||||
'Invalid account recovery key'
|
||||
);
|
||||
|
||||
// Enter new recovery key
|
||||
await login.setRecoveryKey(secondKey);
|
||||
|
@ -149,7 +149,7 @@ test.describe('recovery key test', () => {
|
|||
EmailType.recovery,
|
||||
EmailHeader.link
|
||||
);
|
||||
await page.goto(link, { waitUntil: 'networkidle' });
|
||||
await page.goto(link);
|
||||
await login.setRecoveryKey(key);
|
||||
await recoveryKey.confirmRecoveryKey();
|
||||
|
||||
|
|
|
@ -2,6 +2,11 @@ import { test, expect, newPagesForSync } from '../../lib/fixtures/standard';
|
|||
import { EmailHeader, EmailType } from '../../lib/email';
|
||||
|
||||
test.describe('two step auth', () => {
|
||||
test.beforeEach(async ({}, { project }) => {
|
||||
// 2FA test can be slow because of time to generate recovery keys
|
||||
test.slow();
|
||||
});
|
||||
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293446
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293452
|
||||
test('add and remove totp', async ({
|
||||
|
@ -108,7 +113,7 @@ test.describe('two step auth', () => {
|
|||
await login.setCode(newCodes[0]);
|
||||
await login.submit();
|
||||
|
||||
expect(page.url()).toMatch(settings.url);
|
||||
expect(page.url()).toContain(settings.url);
|
||||
});
|
||||
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293460
|
||||
|
@ -117,7 +122,6 @@ test.describe('two step auth', () => {
|
|||
credentials,
|
||||
pages: { page, login, settings, totp },
|
||||
}, { project }) => {
|
||||
test.slow(project.name !== 'local', 'non-local use more codes');
|
||||
await settings.goto();
|
||||
await settings.totp.clickAdd();
|
||||
const { recoveryCodes } = await totp.enable(credentials);
|
||||
|
@ -128,6 +132,7 @@ test.describe('two step auth', () => {
|
|||
credentials.password,
|
||||
recoveryCodes[i]
|
||||
);
|
||||
await login.page.waitForURL(/settings/);
|
||||
await settings.signOut();
|
||||
}
|
||||
await login.login(
|
||||
|
@ -135,12 +140,13 @@ test.describe('two step auth', () => {
|
|||
credentials.password,
|
||||
recoveryCodes[recoveryCodes.length - 1]
|
||||
);
|
||||
await login.page.waitForURL(/settings/);
|
||||
const link = await target.email.waitForEmail(
|
||||
credentials.email,
|
||||
EmailType.lowRecoveryCodes,
|
||||
EmailHeader.link
|
||||
);
|
||||
await page.goto(link, { waitUntil: 'load' });
|
||||
await page.goto(link);
|
||||
const newCodes = await totp.getRecoveryCodes();
|
||||
expect(newCodes.length).toEqual(recoveryCodes.length);
|
||||
});
|
||||
|
|
|
@ -11,62 +11,44 @@ test.describe('signup here', () => {
|
|||
test.slow();
|
||||
});
|
||||
|
||||
test('with an invalid email', async ({ target, page, pages: { login } }) => {
|
||||
await page.goto(`${target.contentServerUrl}?email=invalid`, {
|
||||
waitUntil: 'networkidle',
|
||||
});
|
||||
expect(await login.getErrorMessage()).toMatch('Invalid parameter: email');
|
||||
});
|
||||
|
||||
test('with an empty email', async ({ target, page, pages: { login } }) => {
|
||||
await page.goto(`${target.contentServerUrl}?email=`, {
|
||||
waitUntil: 'networkidle',
|
||||
});
|
||||
expect(await login.getErrorMessage()).toMatch('Invalid parameter: email');
|
||||
});
|
||||
|
||||
test('signup with email with leading whitespace on the email', async ({
|
||||
test('with an invalid email, empty email query query param', async ({
|
||||
target,
|
||||
page,
|
||||
pages: { login },
|
||||
}) => {
|
||||
const email = login.createEmail();
|
||||
const emailWithoutSpace = email;
|
||||
const emailWithSpace = ' ' + email;
|
||||
await page.goto(`${target.contentServerUrl}?email=invalid`);
|
||||
expect(await login.getErrorMessage()).toContain('Invalid parameter: email');
|
||||
|
||||
await page.goto(`${target.contentServerUrl}?email=`);
|
||||
expect(await login.getErrorMessage()).toContain('Invalid parameter: email');
|
||||
});
|
||||
|
||||
test('signup with email with leading/trailing whitespace on the email', async ({
|
||||
target,
|
||||
page,
|
||||
pages: { login },
|
||||
}) => {
|
||||
let email = login.createEmail();
|
||||
let emailWithoutSpace = email;
|
||||
let emailWithSpace = ' ' + email;
|
||||
await page.goto(target.contentServerUrl);
|
||||
await login.fillOutFirstSignUp(emailWithSpace, password, false);
|
||||
|
||||
// Verify the confirm code header and the email
|
||||
expect(await login.isSignUpCodeHeader()).toBe(true);
|
||||
expect(await login.confirmEmail()).toMatch(emailWithoutSpace);
|
||||
expect(await login.confirmEmail()).toContain(emailWithoutSpace);
|
||||
|
||||
// Need to clear the cache to get the new email
|
||||
await login.clearCache();
|
||||
await page.goto(target.contentServerUrl);
|
||||
await login.fillOutEmailFirstSignIn(emailWithoutSpace, password);
|
||||
|
||||
// Verify the confirm code header
|
||||
expect(await login.isSignUpCodeHeader()).toBe(true);
|
||||
});
|
||||
|
||||
test('signup with email with trailing whitespace on the email', async ({
|
||||
target,
|
||||
page,
|
||||
pages: { login },
|
||||
}) => {
|
||||
const email = login.createEmail();
|
||||
const emailWithoutSpace = email;
|
||||
const emailWithSpace = email + ' ';
|
||||
await page.goto(target.contentServerUrl);
|
||||
email = login.createEmail();
|
||||
emailWithoutSpace = email;
|
||||
emailWithSpace = email + ' ';
|
||||
await login.fillOutFirstSignUp(emailWithSpace, password, false);
|
||||
|
||||
// Verify the confirm code header and the email
|
||||
expect(await login.isSignUpCodeHeader()).toBe(true);
|
||||
expect(await login.confirmEmail()).toMatch(emailWithoutSpace);
|
||||
await login.clearCache();
|
||||
await page.goto(target.contentServerUrl);
|
||||
await login.fillOutEmailFirstSignIn(emailWithoutSpace, password);
|
||||
|
||||
// Verify the confirm code header
|
||||
expect(await login.isSignUpCodeHeader()).toBe(true);
|
||||
expect(await login.confirmEmail()).toContain(emailWithoutSpace);
|
||||
});
|
||||
|
||||
test('signup with invalid email address', async ({
|
||||
|
@ -79,35 +61,33 @@ test.describe('signup here', () => {
|
|||
await login.clickSubmit();
|
||||
|
||||
// Verify the error
|
||||
expect(await login.getTooltipError()).toMatch('Valid email required');
|
||||
expect(await login.getTooltipError()).toContain('Valid email required');
|
||||
});
|
||||
|
||||
test('coppa is empty', async ({ target, page, pages: { login } }) => {
|
||||
test('coppa is empty and too young', async ({
|
||||
target,
|
||||
page,
|
||||
pages: { login },
|
||||
}) => {
|
||||
const email = login.createEmail();
|
||||
await page.goto(target.contentServerUrl);
|
||||
await login.setEmail(email);
|
||||
await login.clickSubmit();
|
||||
await page.waitForURL(/signup/);
|
||||
await login.setPassword(password);
|
||||
await login.confirmPassword(password);
|
||||
await login.clickSubmit();
|
||||
|
||||
// Verify the error
|
||||
expect(await login.getTooltipError()).toMatch(
|
||||
expect(await login.getTooltipError()).toContain(
|
||||
'You must enter your age to sign up'
|
||||
);
|
||||
});
|
||||
|
||||
test('coppa too young', async ({ target, page, pages: { login } }) => {
|
||||
const email = login.createEmail();
|
||||
await page.goto(target.contentServerUrl);
|
||||
await login.setEmail(email);
|
||||
await login.clickSubmit();
|
||||
await login.setPassword(password);
|
||||
await login.confirmPassword(password);
|
||||
await login.setAge('12');
|
||||
await login.clickSubmit();
|
||||
|
||||
// Verify the error
|
||||
// Verify navigated to the cannot create account page
|
||||
await page.waitForURL(/cannot_create_account/);
|
||||
expect(await login.cannotCreateAccountHeader()).toBe(true);
|
||||
});
|
||||
|
||||
|
@ -126,7 +106,7 @@ test.describe('signup here', () => {
|
|||
await login.clickSubmit();
|
||||
|
||||
// Verify the error
|
||||
expect(await login.getTooltipError()).toMatch('Passwords do not match');
|
||||
expect(await login.getTooltipError()).toContain('Passwords do not match');
|
||||
});
|
||||
|
||||
test('form prefill information is cleared after signup->sign out', async ({
|
||||
|
@ -145,16 +125,16 @@ test.describe('signup here', () => {
|
|||
|
||||
// check the email address was cleared
|
||||
expect(await login.isEmailHeader()).toBe(true);
|
||||
expect(await login.getEmailInput()).toMatch('');
|
||||
expect(await login.getEmailInput()).toContain('');
|
||||
|
||||
await login.setEmail(login.createEmail());
|
||||
await login.clickSubmit();
|
||||
|
||||
// check the password was cleared
|
||||
expect(await login.getPasswordInput()).toMatch('');
|
||||
expect(await login.getPasswordInput()).toContain('');
|
||||
});
|
||||
|
||||
test('signup via product page and redirect after confirm', async ({
|
||||
test('signup via relier page and redirect after confirm', async ({
|
||||
pages: { login, relier },
|
||||
}) => {
|
||||
const email = login.createEmail();
|
||||
|
|
|
@ -50,7 +50,7 @@ test.describe('Sign up with code ', () => {
|
|||
await login.fillOutFirstSignUp(email, PASSWORD, false);
|
||||
await login.setCode('1234');
|
||||
await signinTokenCode.clickSubmitButton();
|
||||
expect(await login.getTooltipError()).toMatch(
|
||||
expect(await login.getTooltipError()).toContain(
|
||||
'Invalid or expired confirmation code'
|
||||
);
|
||||
});
|
||||
|
|
|
@ -13,10 +13,7 @@ test.describe('redirect_to', () => {
|
|||
|
||||
async function engageRedirect(page, target, redirectTo) {
|
||||
await page.goto(
|
||||
`${target.contentServerUrl}/confirm_signup_code?redirect_to=${redirectTo}`,
|
||||
{
|
||||
waitUntil: 'networkidle',
|
||||
}
|
||||
`${target.contentServerUrl}/confirm_signup_code?redirect_to=${redirectTo}`
|
||||
);
|
||||
await page.click('button[type=submit]');
|
||||
}
|
||||
|
@ -51,8 +48,13 @@ test.describe('redirect_to', () => {
|
|||
pages: { page },
|
||||
}) => {
|
||||
const redirectTo = `${target.contentServerUrl}/settings`;
|
||||
await engageRedirect(page, target, redirectTo);
|
||||
await page.waitForNavigation();
|
||||
await page.goto(
|
||||
`${target.contentServerUrl}/confirm_signup_code?redirect_to=${redirectTo}`
|
||||
);
|
||||
await page.click('button[type=submit]');
|
||||
|
||||
await page.waitForURL(/settings\?/);
|
||||
|
||||
expect(page.url().startsWith(redirectTo)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ test.describe('severity-1 #smoke', () => {
|
|||
|
||||
await settings.disconnectSync(credentials);
|
||||
|
||||
expect(page.url()).toMatch(login.url);
|
||||
expect(page.url()).toContain(login.url);
|
||||
});
|
||||
|
||||
// https://testrail.stage.mozaws.net/index.php?/cases/view/1293475
|
||||
|
@ -70,7 +70,7 @@ test.describe('severity-3 #smoke', () => {
|
|||
await page.goto('https://addons.mozilla.org/en-US/firefox/');
|
||||
await Promise.all([page.click('text=Log in'), page.waitForNavigation()]);
|
||||
await login.login(credentials.email, credentials.password);
|
||||
expect(page.url()).toMatch(
|
||||
expect(page.url()).toContain(
|
||||
'https://addons.mozilla.org/en-US/firefox/users/edit'
|
||||
);
|
||||
await page.click('text=Delete My Profile');
|
||||
|
@ -96,7 +96,7 @@ test.describe('severity-3 #smoke', () => {
|
|||
page.waitForNavigation(),
|
||||
]);
|
||||
await login.login(credentials.email, credentials.password);
|
||||
expect(page.url()).toMatch('https://getpocket.com/my-list');
|
||||
expect(page.url()).toContain('https://getpocket.com/my-list');
|
||||
await page.click('[aria-label="Open Account Menu"]');
|
||||
await page.click('a:has-text("Log out")');
|
||||
});
|
||||
|
@ -114,7 +114,7 @@ test.describe('severity-3 #smoke', () => {
|
|||
page.waitForNavigation(),
|
||||
]);
|
||||
await login.login(credentials.email, credentials.password);
|
||||
expect(page.url()).toMatch('https://monitor.firefox.com/user/dashboard');
|
||||
expect(page.url()).toContain('https://monitor.firefox.com/user/dashboard');
|
||||
await page.click('#avatar-wrapper');
|
||||
await Promise.all([
|
||||
page.click('text=Sign Out'),
|
||||
|
@ -149,49 +149,3 @@ test.describe('severity-3 #smoke', () => {
|
|||
await expect(page.locator('text=Sign In/Up').first()).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('OAuth and Fx Desktop handshake', () => {
|
||||
test('user signed into browser and OAuth login', async ({
|
||||
target,
|
||||
credentials,
|
||||
}) => {
|
||||
const { page, login, settings, relier } = await newPagesForSync(target);
|
||||
await page.goto(
|
||||
target.contentServerUrl +
|
||||
'?context=fx_desktop_v3&entrypoint=fxa%3Aenter_email&service=sync&action=email'
|
||||
);
|
||||
await login.login(credentials.email, credentials.password);
|
||||
expect(await login.isSyncConnectedHeader()).toBe(true);
|
||||
|
||||
// Normally we wouldn't need this delay, but because we are
|
||||
// disconnecting the sync service, we need to ensure that the device
|
||||
// record and web channels have been sent and created.
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await relier.goto();
|
||||
await relier.clickEmailFirst();
|
||||
|
||||
// User can sign in with cached credentials, no password needed.
|
||||
await expect(await login.getPrefilledEmail()).toMatch(credentials.email);
|
||||
await expect(await login.isCachedLogin()).toBe(true);
|
||||
|
||||
await login.submit();
|
||||
expect(await relier.isLoggedIn()).toBe(true);
|
||||
|
||||
await relier.signOut();
|
||||
|
||||
// Attempt to sign back in
|
||||
await relier.clickEmailFirst();
|
||||
|
||||
await expect(await login.getPrefilledEmail()).toMatch(credentials.email);
|
||||
await expect(await login.isCachedLogin()).toBe(true);
|
||||
|
||||
await login.submit();
|
||||
expect(await relier.isLoggedIn()).toBe(true);
|
||||
|
||||
// Disconnect sync otherwise we can have flaky tests.
|
||||
await settings.disconnectSync(credentials);
|
||||
|
||||
expect(page.url()).toMatch(login.url);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@ test.describe('coupon test', () => {
|
|||
await subscribe.addCouponCode('autoexpired');
|
||||
|
||||
// Verifying the correct error message
|
||||
expect(await subscribe.couponErrorMessageText()).toMatch(
|
||||
expect(await subscribe.couponErrorMessageText()).toContain(
|
||||
'The code you entered has expired'
|
||||
);
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ test.describe('coupon test', () => {
|
|||
await subscribe.addCouponCode('autoinvalid');
|
||||
|
||||
// Asserting that the code is invalid for a 6mo plan
|
||||
expect(await subscribe.couponErrorMessageText()).toMatch(
|
||||
expect(await subscribe.couponErrorMessageText()).toContain(
|
||||
'The code you entered is invalid'
|
||||
);
|
||||
|
||||
|
@ -53,7 +53,7 @@ test.describe('coupon test', () => {
|
|||
await subscribe.addCouponCode('autoinvalid');
|
||||
|
||||
// Asserting that the code is invalid for a 6m plan
|
||||
expect(await subscribe.couponErrorMessageText()).toMatch(
|
||||
expect(await subscribe.couponErrorMessageText()).toContain(
|
||||
'The code you entered is invalid'
|
||||
);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { EmailHeader, EmailType } from '../../lib/email';
|
|||
const password = 'passwordzxcv';
|
||||
let email;
|
||||
|
||||
test.describe.skip('Firefox Desktop Sync v3 sign in', () => {
|
||||
test.describe('Firefox Desktop Sync v3 sign in', () => {
|
||||
test.beforeEach(async ({ pages: { login } }) => {
|
||||
test.slow();
|
||||
email = login.createEmail('sync{id}');
|
||||
|
@ -120,3 +120,49 @@ test.describe.skip('Firefox Desktop Sync v3 sign in', () => {
|
|||
expect(await connectAnotherDevice.fxaConnected.isVisible()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('OAuth and Fx Desktop handshake', () => {
|
||||
test('user signed into browser and OAuth login', async ({
|
||||
target,
|
||||
credentials,
|
||||
}) => {
|
||||
const { page, login, settings, relier } = await newPagesForSync(target);
|
||||
await page.goto(
|
||||
target.contentServerUrl +
|
||||
'?context=fx_desktop_v3&entrypoint=fxa%3Aenter_email&service=sync&action=email'
|
||||
);
|
||||
await login.login(credentials.email, credentials.password);
|
||||
expect(await login.isSyncConnectedHeader()).toBe(true);
|
||||
|
||||
// Normally we wouldn't need this delay, but because we are
|
||||
// disconnecting the sync service, we need to ensure that the device
|
||||
// record and web channels have been sent and created.
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await relier.goto();
|
||||
await relier.clickEmailFirst();
|
||||
|
||||
// User can sign in with cached credentials, no password needed.
|
||||
await expect(await login.getPrefilledEmail()).toContain(credentials.email);
|
||||
await expect(await login.isCachedLogin()).toBe(true);
|
||||
|
||||
await login.submit();
|
||||
expect(await relier.isLoggedIn()).toBe(true);
|
||||
|
||||
await relier.signOut();
|
||||
|
||||
// Attempt to sign back in
|
||||
await relier.clickEmailFirst();
|
||||
|
||||
await expect(await login.getPrefilledEmail()).toContain(credentials.email);
|
||||
await expect(await login.isCachedLogin()).toBe(true);
|
||||
|
||||
await login.submit();
|
||||
expect(await relier.isLoggedIn()).toBe(true);
|
||||
|
||||
// Disconnect sync otherwise we can have flaky tests.
|
||||
await settings.disconnectSync(credentials);
|
||||
|
||||
expect(page.url()).toContain(login.url);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ const password = 'passwordzxcv';
|
|||
const incorrectPassword = 'password123';
|
||||
let email;
|
||||
|
||||
test.describe.skip('Firefox Desktop Sync v3 sign up', () => {
|
||||
test.describe('Firefox Desktop Sync v3 sign up', () => {
|
||||
test.beforeEach(async ({ pages: { login } }) => {
|
||||
test.slow();
|
||||
email = login.createEmail('sync{id}');
|
||||
|
|
|
@ -25,7 +25,7 @@ test.describe('Firefox Desktop Sync v3 reset password', () => {
|
|||
EmailType.recovery,
|
||||
EmailHeader.link
|
||||
);
|
||||
await page.goto(link, { waitUntil: 'load' });
|
||||
await page.goto(link);
|
||||
|
||||
// Enter a short password
|
||||
await resetPassword.resetNewPassword('pass');
|
||||
|
|
|
@ -76,7 +76,7 @@ const execOptions = {
|
|||
},
|
||||
};
|
||||
|
||||
describe.skip('#integration - scripts/bulk-mailer', function () {
|
||||
describe('#integration - scripts/bulk-mailer', function () {
|
||||
this.timeout(10000);
|
||||
|
||||
let db, server;
|
||||
|
|
|
@ -68,7 +68,7 @@ const execOptions = {
|
|||
},
|
||||
};
|
||||
|
||||
describe.skip('#integration - scripts/dump-users', function () {
|
||||
describe('#integration - scripts/dump-users', function () {
|
||||
this.timeout(10000);
|
||||
|
||||
let db, server;
|
||||
|
|
|
@ -58,7 +58,7 @@ const account2Mock = createAccount(
|
|||
|
||||
const DB = require('../../lib/db')(config, log, Token, UnblockCode);
|
||||
|
||||
describe.skip('#integration - scripts/must-reset', async function () {
|
||||
describe('#integration - scripts/must-reset', async function () {
|
||||
this.timeout(30000);
|
||||
|
||||
let db, server;
|
||||
|
|
Загрузка…
Ссылка в новой задаче