mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Add new Grist login page
Summary: Adds a new Grist login page to the login app, and replaces the server-side Cognito Google Sign-In flow with Google's own OAuth flow. Test Plan: Browser and server tests. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D3332
This commit is contained in:
@@ -24,7 +24,7 @@ describe('ActionLog', function() {
|
||||
}
|
||||
|
||||
before(async function() {
|
||||
const session = await gu.session().login();
|
||||
const session = await gu.session().user('user4').login();
|
||||
await session.tempDoc(cleanup, 'Hello.grist');
|
||||
await gu.dismissWelcomeTourIfNeeded();
|
||||
});
|
||||
|
||||
@@ -27,9 +27,9 @@ describe('HomeIntro', function() {
|
||||
const signUp = await driver.findContent('.test-welcome-text a', 'sign up');
|
||||
assert.include(await signUp.getAttribute('href'), '/signin');
|
||||
|
||||
// Check that the link takes us to a login page (either Cognito or Grist, depending on session).
|
||||
// Check that the link takes us to a Grist login page.
|
||||
await signUp.click();
|
||||
await gu.checkSigninPage();
|
||||
await gu.checkLoginPage();
|
||||
await driver.navigate().back();
|
||||
await gu.waitForDocMenuToLoad();
|
||||
});
|
||||
|
||||
@@ -41,9 +41,9 @@ export const simulateLogin = homeUtil.simulateLogin.bind(homeUtil);
|
||||
export const removeLogin = homeUtil.removeLogin.bind(homeUtil);
|
||||
export const setValue = homeUtil.setValue.bind(homeUtil);
|
||||
export const isOnLoginPage = homeUtil.isOnLoginPage.bind(homeUtil);
|
||||
export const isOnGristLoginPage = homeUtil.isOnLoginPage.bind(homeUtil);
|
||||
export const checkLoginPage = homeUtil.checkLoginPage.bind(homeUtil);
|
||||
export const checkGristLoginPage = homeUtil.checkGristLoginPage.bind(homeUtil);
|
||||
export const checkSigninPage = homeUtil.checkSigninPage.bind(homeUtil);
|
||||
|
||||
export const fixturesRoot: string = testUtils.fixturesRoot;
|
||||
|
||||
@@ -1333,6 +1333,7 @@ export enum TestUserEnum {
|
||||
user1 = 'chimpy',
|
||||
user2 = 'charon',
|
||||
user3 = 'kiwi',
|
||||
user4 = 'ham',
|
||||
owner = 'chimpy',
|
||||
anon = 'anon',
|
||||
support = 'support',
|
||||
|
||||
@@ -6,6 +6,7 @@ import * as fse from 'fs-extra';
|
||||
import defaults = require('lodash/defaults');
|
||||
import {WebElement} from 'mocha-webdriver';
|
||||
import fetch from 'node-fetch';
|
||||
import {authenticator} from 'otplib';
|
||||
import * as path from 'path';
|
||||
import {WebDriver} from 'selenium-webdriver';
|
||||
|
||||
@@ -46,7 +47,7 @@ export class HomeUtil {
|
||||
* (after having been created if necessary), so that their home api can be later
|
||||
* instantiated without page loads.
|
||||
* When testing against an external server, the simulated login is in fact genuine,
|
||||
* done via Cognito.
|
||||
* done via the Grist login page.
|
||||
*/
|
||||
public async simulateLogin(name: string, email: string, org: string = "", options: {
|
||||
loginMethod?: UserProfile['loginMethod'],
|
||||
@@ -75,26 +76,22 @@ export class HomeUtil {
|
||||
}
|
||||
// Make sure we revisit page in case login is changing.
|
||||
await this.driver.get('about:blank');
|
||||
// When running against an external server, we log in through Cognito.
|
||||
// When running against an external server, we log in through the Grist login page.
|
||||
await this.driver.get(this.server.getUrl(org, ""));
|
||||
if (!(await this.isOnSigninPage())) {
|
||||
if (!await this.isOnLoginPage()) {
|
||||
// Explicitly click sign-in link if necessary.
|
||||
await this.driver.findWait('.test-user-signin', 4000).click();
|
||||
await this.driver.findContentWait('.grist-floating-menu a', 'Sign in', 500).click();
|
||||
}
|
||||
// Check if we need to switch to Cognito login from the Grist sign-up page.
|
||||
if (await this.isOnGristLoginPage()) {
|
||||
await this.driver.findWait('a[href*="login?"]', 4000).click();
|
||||
}
|
||||
|
||||
// Fill the login form (either on /test/login or Cognito).
|
||||
// Fill the login form (either test or Grist).
|
||||
if (await this.isOnTestLoginPage()) {
|
||||
await this.fillTestLoginForm(email, name);
|
||||
} else {
|
||||
await this.fillLoginForm(email);
|
||||
await this.fillGristLoginForm(email);
|
||||
}
|
||||
|
||||
if (!(await this.isWelcomePage()) && (options.freshAccount || options.isFirstLogin)) {
|
||||
if (!await this.isWelcomePage() && (options.freshAccount || options.isFirstLogin)) {
|
||||
await this._recreateCurrentUser(email, org, name);
|
||||
}
|
||||
}
|
||||
@@ -148,29 +145,43 @@ export class HomeUtil {
|
||||
await form.find('input[name="signInSubmitButton"]').click();
|
||||
}
|
||||
|
||||
// Fill up a Cognito login page. If on a signup page, switch to a login page.
|
||||
// TEST_ACCOUNT_PASSWORD must be set, or a password provided. Should be on a Cognito
|
||||
// login/signup page before calling this method.
|
||||
public async fillLoginForm(email: string, password?: string) {
|
||||
/**
|
||||
* Fill up the Grist login page form, and submit. If called with a user that
|
||||
* has TOTP-based 2FA enabled, TEST_ACCOUNT_TOTP_SECRET must be set for a valid
|
||||
* code to be submitted on the following form.
|
||||
*
|
||||
* Should be on the Grist login or sign-up page before calling this method. If
|
||||
* `password` is not passed in, TEST_ACCOUNT_PASSWORD must be set.
|
||||
*/
|
||||
public async fillGristLoginForm(email: string, password?: string) {
|
||||
if (!password) {
|
||||
password = process.env.TEST_ACCOUNT_PASSWORD;
|
||||
if (!password) {
|
||||
throw new Error('TEST_ACCOUNT_PASSWORD not set');
|
||||
}
|
||||
}
|
||||
await this.checkLoginPage();
|
||||
await this.checkGristLoginPage();
|
||||
if ((await this.driver.getCurrentUrl()).match(/signup\?/)) {
|
||||
await this.driver.findWait('a[href*="login?"]', 4000).click();
|
||||
}
|
||||
// There are two login forms, one hidden, one shown. Pick the one that is shown.
|
||||
const block =
|
||||
(await this.driver.find('div.modal-content-desktop').isDisplayed()) ?
|
||||
(await this.driver.find('div.modal-content-desktop')) :
|
||||
(await this.driver.find('div.modal-content-mobile'));
|
||||
await block.findWait('input[name="username"]', 4000);
|
||||
await this.setValue(block.findWait('input[name="username"]', 4000), email);
|
||||
await this.setValue(block.findWait('input[name="password"]', 4000), password);
|
||||
await block.find('input[name="signInSubmitButton"]').click();
|
||||
|
||||
await this.driver.findWait('input[name="email"]', 4000).sendKeys(email);
|
||||
await this.driver.find('input[name="password"]').sendKeys(password);
|
||||
await this.driver.find('.test-lp-sign-in').click();
|
||||
await this.driver.wait(async () => !await this.isOnGristLoginPage(), 4000);
|
||||
if (!await this.driver.findContent('.test-mfa-title', 'Almost there!').isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const secret = process.env.TEST_ACCOUNT_TOTP_SECRET;
|
||||
if (!secret) { throw new Error('TEST_ACCOUNT_TOTP_SECRET not set'); }
|
||||
|
||||
const code = authenticator.generate(secret);
|
||||
await this.driver.find('input[name="verificationCode"]').sendKeys(code);
|
||||
await this.driver.find('.test-mfa-submit').click();
|
||||
await this.driver.wait(async () => {
|
||||
return !await this.driver.findContent('.test-mfa-title', 'Almost there!').isPresent();
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,18 +286,19 @@ export class HomeUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are currently on the Cognito or test login page.
|
||||
* Returns whether we are currently on any login page (including the test page).
|
||||
*/
|
||||
public async isOnLoginPage() {
|
||||
const url = await this.driver.getCurrentUrl();
|
||||
return /^https:\/\/gristlogin/.test(url) || await this.isOnTestLoginPage();
|
||||
return await this.isOnGristLoginPage() || await this.isOnTestLoginPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are currently on a Grist login page.
|
||||
*/
|
||||
public async isOnGristLoginPage() {
|
||||
return /^https:\/\/login(-s)?\.getgrist\.com/.test(await this.driver.getCurrentUrl());
|
||||
const isOnSignupPage = await this.driver.find('.test-sp-heading').isPresent();
|
||||
const isOnLoginPage = await this.driver.find('.test-lp-heading').isPresent();
|
||||
return isOnSignupPage || isOnLoginPage;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,14 +309,7 @@ export class HomeUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are currently on any sign-in page (e.g. Cognito, Grist, test).
|
||||
*/
|
||||
public async isOnSigninPage() {
|
||||
return await this.isOnLoginPage() || await this.isOnGristLoginPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for browser to navigate to the Cognito login page.
|
||||
* Waits for browser to navigate to any login page (including the test page).
|
||||
*/
|
||||
public async checkLoginPage(waitMs: number = 2000) {
|
||||
await this.driver.wait(this.isOnLoginPage.bind(this), waitMs);
|
||||
@@ -317,13 +322,6 @@ export class HomeUtil {
|
||||
await this.driver.wait(this.isOnGristLoginPage.bind(this), waitMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for browser to navigate to any sign-in page (e.g. Cognito, Grist, test).
|
||||
*/
|
||||
public async checkSigninPage(waitMs: number = 4000) {
|
||||
await this.driver.wait(this.isOnSigninPage.bind(this), waitMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete and recreate the user, via the specified org. The specified user must be
|
||||
* currently logged in!
|
||||
@@ -335,11 +333,11 @@ export class HomeUtil {
|
||||
await this.driver.findWait('.test-user-signin', 4000).click();
|
||||
await this.driver.findContentWait('.grist-floating-menu a', 'Sign in', 500).click();
|
||||
await this.checkLoginPage();
|
||||
// Fill the login form (either on /test/login or Cognito).
|
||||
// Fill the login form (either test or Grist).
|
||||
if (await this.isOnTestLoginPage()) {
|
||||
await this.fillTestLoginForm(email, name);
|
||||
} else {
|
||||
await this.fillLoginForm(email);
|
||||
await this.fillGristLoginForm(email);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user