Skip to content

Commit

Permalink
Add basic test for sign in/out
Browse files Browse the repository at this point in the history
  • Loading branch information
rwood-moz committed Dec 10, 2024
1 parent aa7a69c commit 9dcc5c9
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 4 deletions.
8 changes: 5 additions & 3 deletions frontend/src/views/LoginView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ const onEnter = () => {
</div>
<div class="form-body">
<form v-if="loginStep !== LoginSteps.SignUpConfirm" class="form" ref="formRef" autocomplete="off" @submit.prevent @keyup.enter="() => onEnter()">
<text-input name="email" v-model="email" :required="true">{{ t('login.form.email') }}</text-input>
<text-input v-if="isPasswordAuth" name="password" v-model="password" :required="true" type="password">{{ t('label.password') }}</text-input>
<text-input v-if="loginStep === LoginSteps.SignUp && !hideInviteField" name="inviteCode" v-model="inviteCode" :help="t('login.form.no-invite-code')">{{ t('label.inviteCode') }}</text-input>
<text-input name="email" v-model="email" :required="true" data-testid="login-email-input">{{ t('login.form.email') }}</text-input>
<text-input v-if="isPasswordAuth" name="password" v-model="password" :required="true" type="password" data-testid="login-password-input">{{ t('label.password') }}</text-input>
<text-input v-if="loginStep === LoginSteps.SignUp && !hideInviteField" name="inviteCode" v-model="inviteCode" :help="t('login.form.no-invite-code')" data-testid="login-invite-code-input">{{ t('label.inviteCode') }}</text-input>
</form>
</div>
<template v-slot:actions>
Expand All @@ -226,6 +226,7 @@ const onEnter = () => {
:disabled="isLoading"
@click="onEnter()"
v-if="loginStep !== LoginSteps.SignUpConfirm"
data-testid="login-continue-btn"
>
{{ t('label.continue') }}
</primary-button>
Expand All @@ -235,6 +236,7 @@ const onEnter = () => {
:disabled="isLoading"
@click="router.push({name: 'home'})"
v-else
data-testid="login-close-btn"
>
{{ t('label.close') }}
</primary-button>
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/const/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ export const APPT_PROD_URL = 'https://appointment.day/';

// page titles
export const APPT_PAGE_TITLE = 'Thunderbird Appointment';
export const FXA_PAGE_TITLE = 'Mozilla accounts';

// production sign-in credentials
export const PROD_LOGIN_EMAIL = process.env.APPT_PROD_LOGIN_EMAIL;
export const PROD_LOGIN_PWORD = process.env.APPT_PROD_LOGIN_PWORD;
15 changes: 15 additions & 0 deletions test/e2e/pages/fxa-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { type Page, type Locator } from '@playwright/test';

export class FxAPage {
readonly page: Page;
readonly signInHeaderText: Locator;
readonly userAvatar: Locator;
readonly signInButton: Locator;

constructor(page: Page) {
this.page = page;
this.signInHeaderText = this.page.getByText('Enter your password');
this.userAvatar = this.page.getByTestId('avatar-default');
this.signInButton = this.page.locator('button:text("Sign in")');
}
}
24 changes: 23 additions & 1 deletion test/e2e/pages/splashscreen-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,36 @@ export class SplashscreenPage {
readonly page: Page;
readonly loginBtn: Locator;
readonly signUpBetaBtn: Locator;
readonly loginEmailInput: Locator;
readonly loginContinueBtn: Locator;

constructor(page: Page) {
this.page = page;
this.loginBtn = this.page.getByTestId('home-login-btn');
//update this after data-testid 's are deployed to prod
//this.loginBtn = this.page.getByTestId('home-login-btn');
this.loginBtn = this.page.getByTitle('Log in');
this.signUpBetaBtn = this.page.getByTestId('home-sign-up-beta-btn');
//update this after data-testid 's are deployed to prod
//this.loginEmailInput = this.page.getByTestId('login-email-input');
this.loginEmailInput = this.page.getByLabel('Email address');
//update this after data-testid 's are deployed to prod
//this.loginContinueBtn = this.page.getByTestId('login-continue-btn');
this.loginContinueBtn = this.page.getByTitle('Continue');
}

async gotoProd() {
await this.page.goto(APPT_PROD_URL);
}

async clickLoginBtn() {
await this.loginBtn.click();
}

async clickLoginContinueBtn() {
await this.loginContinueBtn.click();
}

async enterLoginEmail(emailAddress: string) {
await this.loginEmailInput.fill(emailAddress);
}
}
46 changes: 46 additions & 0 deletions test/e2e/tests/sign-in.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { test, expect } from '@playwright/test';
import { SplashscreenPage } from '../pages/splashscreen-page';
import { FxAPage } from '../pages/fxa-page';
import { PROD_LOGIN_EMAIL, FXA_PAGE_TITLE } from '../const/constants';

let splashscreen: SplashscreenPage;
let fxa_sign_in: FxAPage;

test.beforeEach(async ({ page }) => {
// navigate to the main appointment page (splashscreen)
splashscreen = new SplashscreenPage(page);
fxa_sign_in = new FxAPage(page);
await splashscreen.gotoProd();
});

// verify basic sign-in flow works
test.describe('basic sign-in flow', {
tag: '@prod-sanity'
}, () => {
test('clicking login button brings up the sign-in dialog', async ({ page }) => {
await expect(splashscreen.loginBtn).toBeVisible();
await splashscreen.clickLoginBtn();
await expect(splashscreen.loginEmailInput).toBeVisible();
await expect(splashscreen.loginContinueBtn).toBeVisible();
});

test('clicking continue button on login dialog brings up the FxA sign-in dialog', async ({ page }) => {
await expect(splashscreen.loginBtn).toBeVisible();
await splashscreen.clickLoginBtn();
expect(PROD_LOGIN_EMAIL, 'getting APPT_PROD_LOGIN_EMAIL env var').toBeTruthy();
await splashscreen.enterLoginEmail(String(PROD_LOGIN_EMAIL))
await splashscreen.clickLoginContinueBtn();
await expect(page).toHaveTitle(FXA_PAGE_TITLE);
await expect(fxa_sign_in.signInHeaderText).toBeVisible({ timeout: 30_000 }); // be generous in case FxA is slow to load
await expect(fxa_sign_in.userAvatar).toBeVisible();
await expect(fxa_sign_in.signInButton).toBeVisible();
});

// todo fill out sign-in dialog etc. use the splashscreen-page object model is fine
test('able to sign-in to appointment', async ({ page }) => {
// todo fill out email address field, password field, and click continue button
// => use credentials set via local env vars (will set via secrets in CI)
// add a splashscreen.signOut() and use that; then verify here (dashbaord appears)
expect(true).toBeTruthy();
});
});
25 changes: 25 additions & 0 deletions test/e2e/tests/sign-out.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { test, expect } from '@playwright/test';
import { SplashscreenPage } from '../pages/splashscreen-page';
import { APPT_PAGE_TITLE } from '../const/constants';

let splashscreen: SplashscreenPage;

test.beforeEach(async ({ page }) => {
// navigate to the main appointment page (splashscreen)
splashscreen = new SplashscreenPage(page);
await splashscreen.gotoProd();
// todo fill out email address field, password field, and click continue button
// => use credentials set via local env vars (will set via secrets in CI)
// then verifiy sign-in was successful - dashboard appears
// use splashscreen-page signOn() method
});

// verify main appointment splash screen appears correctly
test.describe('basic sign-out flow', {
tag: '@prod-sanity'
}, () => {
test('able to sign-out of appointment', async ({ page }) => {
// todo sign out and verify splashscreen appears with login button visible
expect(true).toBeTruthy();
});
});

0 comments on commit 9dcc5c9

Please sign in to comment.