[Onboarding Flow] Answer compatibility questions in the test suite for onboarding (#35)

* Fixed Type errors

* Added Database checks to the onboarding flow

* Updated Onboarding flow
Changed type ChildrenExpectation so that it can be used for database verification

* Added compatibility page setup
Added more compatibility questions

* Finished up the onboarding flow suite
Added compatibility question tests and verifications
Updated tests to cover Keywords and Headline changes recently made
Updated tests to cover all of the big5 personality traits

* Apply suggestions from code review

---------

Co-authored-by: Martin Braquet <martin.braquet@gmail.com>
This commit is contained in:
Okechi Jones-Williams
2026-03-04 10:05:56 +00:00
committed by GitHub
parent 140ace55bf
commit e115df8e11
15 changed files with 559 additions and 203 deletions

View File

@@ -5,7 +5,7 @@ export const RELATIONSHIP_CHOICES = {
Collaboration: 'collaboration',
Friendship: 'friendship',
Relationship: 'relationship',
}
} as const
export const RELATIONSHIP_STATUS_CHOICES = {
Single: 'single',
@@ -13,13 +13,13 @@ export const RELATIONSHIP_STATUS_CHOICES = {
'In casual relationship': 'casual',
'In long-term relationship': 'long_term',
'In open relationship': 'open',
}
} as const
export const ROMANTIC_CHOICES = {
Monogamous: 'mono',
Polyamorous: 'poly',
'Open Relationship': 'open',
}
} as const
export const POLITICAL_CHOICES = {
Progressive: 'progressive',
@@ -35,7 +35,7 @@ export const POLITICAL_CHOICES = {
'Effective Accelerationism': 'e/acc',
'Pause AI / Tech Skeptic': 'pause ai',
'Independent / Other': 'other',
}
} as const
export const DIET_CHOICES = {
Omnivore: 'omnivore',
@@ -45,7 +45,7 @@ export const DIET_CHOICES = {
Paleo: 'paleo',
Pescetarian: 'pescetarian',
Other: 'other',
}
} as const
export const EDUCATION_CHOICES = {
'High school': 'high-school',
@@ -53,7 +53,7 @@ export const EDUCATION_CHOICES = {
Bachelors: 'bachelors',
Masters: 'masters',
PhD: 'doctorate',
}
} as const
export const RELIGION_CHOICES = {
Atheist: 'atheist',
@@ -72,7 +72,7 @@ export const RELIGION_CHOICES = {
Zoroastrian: 'zoroastrian',
'Unitarian Universalist': 'unitarian_universalist',
Other: 'other',
}
} as const
export const LANGUAGE_CHOICES = {
Akan: 'akan',
@@ -176,7 +176,7 @@ export const LANGUAGE_CHOICES = {
Yue: 'yue',
Zhuang: 'zhuang',
Zulu: 'zulu',
}
} as const
export const LOCALE_TO_LANGUAGE: Record<string, string> = {
en: 'english',
@@ -193,7 +193,7 @@ export const RACE_CHOICES = {
'Middle Eastern': 'middle_eastern',
'Native American/Indigenous': 'native_american',
Other: 'other',
}
} as const
export const MBTI_CHOICES = {
INTJ: 'intj',
@@ -218,13 +218,13 @@ export const GENDERS = {
Woman: 'female',
Man: 'male',
Other: 'other',
}
} as const
export const GENDERS_PLURAL = {
Women: 'female',
Men: 'male',
Other: 'other',
}
} as const
export const LAST_ONLINE_CHOICES = {
today: 'Today',
@@ -249,13 +249,37 @@ export const INVERTED_GENDERS = invert(GENDERS)
export const INVERTED_LAST_ONLINE_CHOICES = invert(LAST_ONLINE_CHOICES)
//Exported types for test files to use when referencing the keys of the choices objects
export type ConnectionTypeKey = keyof typeof RELATIONSHIP_CHOICES
export type RelationshipStatusKey = keyof typeof RELATIONSHIP_STATUS_CHOICES
export type RelationshipStyleKey = keyof typeof ROMANTIC_CHOICES
export type PoliticalBeliefsKey = keyof typeof POLITICAL_CHOICES
export type DietKey = keyof typeof DIET_CHOICES
export type EducationKey = keyof typeof EDUCATION_CHOICES
export type ReligionKey = keyof typeof RELIGION_CHOICES
export type LanguageKey = keyof typeof LANGUAGE_CHOICES
export type EthnicityKey = keyof typeof RACE_CHOICES
export type PersonalityKey = keyof typeof MBTI_CHOICES
export type ConnectionTypeTuple = {
[K in keyof typeof RELATIONSHIP_CHOICES]: [K, (typeof RELATIONSHIP_CHOICES)[K]]
}[keyof typeof RELATIONSHIP_CHOICES]
export type RelationshipStatusTuple = {
[K in keyof typeof RELATIONSHIP_STATUS_CHOICES]: [K, (typeof RELATIONSHIP_STATUS_CHOICES)[K]]
}[keyof typeof RELATIONSHIP_STATUS_CHOICES]
export type RelationshipStyleTuple = {
[K in keyof typeof ROMANTIC_CHOICES]: [K, (typeof ROMANTIC_CHOICES)[K]]
}[keyof typeof ROMANTIC_CHOICES]
export type PoliticalTuple = {
[K in keyof typeof POLITICAL_CHOICES]: [K, (typeof POLITICAL_CHOICES)[K]]
}[keyof typeof POLITICAL_CHOICES]
export type DietTuple = {
[K in keyof typeof DIET_CHOICES]: [K, (typeof DIET_CHOICES)[K]]
}[keyof typeof DIET_CHOICES]
export type EducationTuple = {
[K in keyof typeof EDUCATION_CHOICES]: [K, (typeof EDUCATION_CHOICES)[K]]
}[keyof typeof EDUCATION_CHOICES]
export type ReligionTuple = {
[K in keyof typeof RELIGION_CHOICES]: [K, (typeof RELIGION_CHOICES)[K]]
}[keyof typeof RELIGION_CHOICES]
export type LanguageTuple = {
[K in keyof typeof LANGUAGE_CHOICES]: [K, (typeof LANGUAGE_CHOICES)[K]]
}[keyof typeof LANGUAGE_CHOICES]
export type EthnicityTuple = {
[K in keyof typeof RACE_CHOICES]: [K, (typeof RACE_CHOICES)[K]]
}[keyof typeof RACE_CHOICES]
export type GenderTuple = {
[K in keyof typeof GENDERS]: [K, (typeof GENDERS)[K]]
}[keyof typeof GENDERS]
export type InterestedInGenderTuple = {
[K in keyof typeof GENDERS_PLURAL]: [K, (typeof GENDERS_PLURAL)[K]]
}[keyof typeof GENDERS_PLURAL]

View File

@@ -36,6 +36,12 @@ export const LOCALES = {
fr: 'Français',
de: 'Deutsch',
// es: "Español",
}
} as const
export const supportedLocales = Object.keys(LOCALES)
export type Locale = (typeof supportedLocales)[number]
//Exported types for test files to use when referencing the keys of the choices objects
export type LocaleTuple = {
[K in keyof typeof LOCALES]: [K, (typeof LOCALES)[K]]
}[keyof typeof LOCALES]

View File

@@ -1,6 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
"jsx": "react-jsx",
"moduleResolution": "node",
"noImplicitReturns": true,
"outDir": "./dist",

View File

@@ -1,30 +1,94 @@
import {expect, Locator, Page} from '@playwright/test'
import { LocaleTuple } from "common/constants";
export class HomePage {
private readonly homePageLink: Locator
private readonly aboutLink: Locator
private readonly faqLink: Locator
private readonly voteLink: Locator
private readonly eventsLink: Locator
private readonly whatsNewLink: Locator
private readonly socialsLink: Locator
private readonly organizationLink: Locator
private readonly contactLink: Locator
private readonly signUpButton: Locator
private readonly localePicker: Locator
private readonly signInLink: Locator
private readonly closeButton: Locator
constructor(public readonly page: Page) {
this.homePageLink = page.getByText('Compass dev', {exact: true})
this.aboutLink = page.locator('span:has-text("About")')
this.faqLink = page.getByText('FAQ', {exact: true})
this.voteLink = page.getByText('Vote', {exact: true})
this.homePageLink = page.getByText('Compass', { exact: true})
this.aboutLink = page.getByTestId('sidebar-about')
this.faqLink = page.getByTestId('sidebar-faq')
this.voteLink = page.getByTestId('sidebar-vote')
this.eventsLink = page.getByTestId('sidebar-events')
this.whatsNewLink = page.getByTestId('sidebar-news')
this.socialsLink = page.getByTestId('sidebar-social')
this.organizationLink = page.getByTestId('sidebar-organization')
this.contactLink = page.getByTestId('sidebar-contact')
this.signUpButton = page.locator('button').filter({hasText: 'Sign up'}).first()
this.signInLink = page.locator('span:has-text("Sign in")')
this.localePicker = page.getByTestId('sidebar-locale-picker')
this.signInLink = page.getByTestId('sidebar-signin')
this.closeButton = page.getByRole('button', {name: 'Close'})
}
async gotToHomePage() {
await this.page.goto('/')
}
async clickAboutLink() {
await expect(this.aboutLink).toBeVisible()
await this.aboutLink.click()
}
async clickFaqLink() {
await expect(this.faqLink).toBeVisible()
await this.faqLink.click()
}
async clickVoteLink() {
await expect(this.voteLink).toBeVisible()
await this.voteLink.click()
}
async clickEventsLink() {
await expect(this.eventsLink).toBeVisible()
await this.eventsLink.click()
}
async clickWhatsNewLink() {
await expect(this.whatsNewLink).toBeVisible()
await this.whatsNewLink.click()
}
async clickSocialsLink() {
await expect(this.socialsLink).toBeVisible()
await this.socialsLink.click()
}
async clickOrganizationLink() {
await expect(this.organizationLink).toBeVisible()
await this.organizationLink.click()
}
async clickContactLink() {
await expect(this.contactLink).toBeVisible()
await this.contactLink.click()
}
async clickSignUpButton() {
await expect(this.signUpButton).toBeVisible()
await this.signUpButton.click()
}
async setLocale(locale: LocaleTuple) {
if (!locale) return;
await expect(this.localePicker).toBeVisible()
await this.localePicker.selectOption(locale[0])
}
async clickSignInLink() {
await expect(this.signInLink).toBeVisible()
await this.signInLink.click()
}
}

View File

@@ -1,6 +1,6 @@
import {expect, Locator, Page} from '@playwright/test'
import {Socials} from '../utils/accountInformation'
import { ImportanceTuple } from "web/components/answers/answer-compatibility-question-content"
import {Socials, Compatibility} from '../utils/accountInformation'
type ProfileDropdownOptions = 'Public' | 'Private' | 'Disable'
@@ -16,6 +16,8 @@ export class ProfilePage {
private readonly disableProfileDropdownOption: Locator
private readonly displayNameAndAgeSection: Locator
private readonly genderLocationHightInInchesSection: Locator
private readonly headlineSection: Locator
private readonly keywordsSection: Locator
private readonly politicalAboutSection: Locator
private readonly relegiousAboutSection: Locator
private readonly interestsAboutSection: Locator
@@ -40,10 +42,24 @@ export class ProfilePage {
private readonly socialMediaSection: Locator
private readonly bioSection: Locator
private readonly bioOptionsDropdown: Locator
private readonly editBioDropdownOptions: Locator
private readonly deleteBioDropdownOptions: Locator
private readonly editDropdownOptions: Locator
private readonly deleteDropdownOptions: Locator
private readonly answerCoreQuestionsButton: Locator
private readonly viewQuestionListButton: Locator
private readonly compatibilityQuestion: Locator
private readonly compatibilityQuestionYourChoices: Locator
private readonly compatibilityQuestionAnswersYouAccept: Locator
private readonly compatibilityQuestionSkipButton: Locator
private readonly compatibilityQuestionNextButton: Locator
private readonly compatibilityQuestionFinishButton: Locator
private readonly compatibilityQuestionThoughts: Locator
private readonly profileCompatibilitySection: Locator
private readonly profileCompatibilityQuestion: Locator
private readonly profileCompatibilityImportance: Locator
private readonly profileCompatibilityDropdown: Locator
private readonly profileCompatibilityAnswer: Locator
private readonly profileCompatibilityAcceptableAnswer: Locator
private readonly profileCompatibilityExplanation: Locator
constructor(public readonly page: Page) {
this.startAnsweringButton = page.getByRole('button', {})
@@ -55,12 +71,14 @@ export class ProfilePage {
this.listProfilePubliclyDropdownOption = page.getByText('List Profile Publicly', {exact: true})
this.limitProfileToMembersDropdownOption = page.getByText('Limit to Members Only', {
exact: true,
})
});
this.disableProfileDropdownOption = page.getByText('Disable profile', {exact: true})
this.headlineSection = page.getByTestId('profile-headline')
this.keywordsSection = page.getByTestId('profile-keywords')
this.displayNameAndAgeSection = page.getByTestId('profile-display-name-age')
this.genderLocationHightInInchesSection = page.getByTestId(
this.genderLocationHightInInchesSection = page.getByTestId(
'profile-gender-location-height-inches',
)
);
this.politicalAboutSection = page.getByTestId('profile-about-political')
this.relegiousAboutSection = page.getByTestId('profile-about-religious')
this.interestsAboutSection = page.getByTestId('profile-about-interests')
@@ -87,31 +105,148 @@ export class ProfilePage {
this.socialMediaSection = page.getByTestId('profile-social-media-accounts')
this.bioSection = page.getByTestId('profile-bio')
this.bioOptionsDropdown = page.getByTestId('profile-bio-options')
this.editBioDropdownOptions = page.getByText('Edit', {exact: true})
this.deleteBioDropdownOptions = page.getByText('Delete', {exact: true})
this.editDropdownOptions = page.getByText('Edit', {exact: true})
this.deleteDropdownOptions = page.getByText('Delete', {exact: true})
this.answerCoreQuestionsButton = page.getByRole('button', {name: 'Answer Core Questions'})
this.viewQuestionListButton = page.getByRole('link', {name: 'View List of Questions'})
this.compatibilityQuestion = page.getByTestId('compatibility-question')
this.compatibilityQuestionYourChoices = page.getByTestId('compatibility-question-your-answer')
this.compatibilityQuestionAnswersYouAccept = page.getByTestId('compatibility-answers-you-accept')
this.compatibilityQuestionThoughts = page.getByTestId('compatibility-question-thoughts')
this.compatibilityQuestionSkipButton = page.getByRole('button', { name: 'Skip' })
this.compatibilityQuestionNextButton = page.getByText('Next', { exact: true })
this.compatibilityQuestionFinishButton = page.getByRole('button', { name: 'Finish' })
this.profileCompatibilitySection = page.getByTestId('profile-compatibility-section')
this.profileCompatibilityQuestion = page.getByTestId('profile-compatibility-question')
this.profileCompatibilityImportance = page.getByTestId('profile-compatibility-importance')
this.profileCompatibilityAnswer = page.getByTestId('profile-compatibility-question-answer')
this.profileCompatibilityAcceptableAnswer = page.getByTestId('profile-compatibility-question-acceptable-answer')
this.profileCompatibilityExplanation = page.getByTestId('profile-compatibility-question-answer-explanation')
this.profileCompatibilityDropdown = page.getByTestId('profile-compatibility-dropdown')
}
async answerCompatibilityQuestion(compatibility: Compatibility | undefined) {
if (!compatibility) return
await expect(this.compatibilityQuestion).toBeVisible()
const question = await this.compatibilityQuestion.textContent()
await expect(this.compatibilityQuestionYourChoices).toBeVisible()
await expect(this.page.getByTestId(`compatibility-your-answer-${compatibility.answer}`)).toBeVisible()
const myAnswer = await this.page.getByTestId(`compatibility-your-answer-${compatibility.answer}`).textContent();
await this.page.getByTestId(`compatibility-your-answer-${compatibility.answer}`).click()
await expect(this.compatibilityQuestionAnswersYouAccept).toBeVisible()
let answersYouAccept = []
for (const answer of compatibility.acceptableAnswers) {
await expect(this.page.getByTestId(`compatibility-answers-you-accept-${answer}`)).toBeVisible()
const textContent = await this.page.getByTestId(`compatibility-answers-you-accept-${answer}`).textContent()
await this.page.getByTestId(`compatibility-answers-you-accept-${answer}`).click()
answersYouAccept.push(textContent)
}
await expect(this.page.getByTestId(`compatibility-question-importance-${compatibility.importance[1]}`)).toBeVisible()
await this.page.getByTestId(`compatibility-question-importance-${compatibility.importance[1]}`).click()
await expect(this.compatibilityQuestionThoughts).toBeVisible()
await this.compatibilityQuestionThoughts.fill(compatibility.explanation)
return {
question,
my_answer: myAnswer,
explanation: compatibility.explanation,
answers_you_accept: answersYouAccept,
importance: compatibility.importance,
}
}
async verifyCompatibilityAnswers(compatInfo: {
question: string | null,
my_answer: string | null,
answers_you_accept: (string | null)[],
importance: ImportanceTuple,
explanation: string
} | undefined) {
if (!compatInfo) return
const questionIndex = await this.profileCompatibilitySection.count()
await expect(questionIndex).toBeGreaterThan(0)
const target = compatInfo.question ?? ''
let matchIndex = -1
for (let i = 0; i < questionIndex; i++) {
const element = (await this.profileCompatibilitySection.nth(i).textContent()) ?? ''
if (target && element.includes(target)) {
matchIndex = i
break
}
}
await expect(matchIndex).toBeGreaterThanOrEqual(0)
await expect(this.profileCompatibilitySection.nth(matchIndex)).toBeVisible()
const question = await this.profileCompatibilitySection.nth(matchIndex).getByTestId('profile-compatibility-question').textContent()
await expect(question).toContain(compatInfo.question)
const importance = await this.profileCompatibilitySection.nth(matchIndex).getByTestId('profile-compatibility-importance').textContent()
await expect(importance).toContain(compatInfo.importance[0])
const answer = await this.profileCompatibilitySection.nth(matchIndex).getByTestId('profile-compatibility-question-answer').textContent()
await expect(answer).toContain(compatInfo.my_answer)
const answerExplanation = await this.profileCompatibilitySection.nth(matchIndex).getByTestId('profile-compatibility-question-answer-explanation').textContent()
await expect(answerExplanation).toContain(compatInfo.explanation)
const acceptableAnswer = await this.profileCompatibilitySection.nth(matchIndex).getByTestId('profile-compatibility-question-acceptable-answer').textContent()
for (let i = 0; i < compatInfo.answers_you_accept.length; i++) {
const item = compatInfo.answers_you_accept[i];
await expect(acceptableAnswer).toContain(item)
}
}
async setCompatibilityQuestionImportance(importance: ImportanceTuple) {
await expect(this.page.getByTestId(`compatibility-question-importance-${importance[1]}`)).toBeVisible()
await this.page.getByTestId(`compatibility-question-importance-${importance[1]}`).click()
}
async clickSkipCompatibilityQuestionButton() {
await expect(this.compatibilityQuestionSkipButton).toBeVisible()
await this.compatibilityQuestionSkipButton.click()
}
async clickNextCompatibilityQuestionButton() {
await expect(this.compatibilityQuestionNextButton).toBeVisible()
await this.compatibilityQuestionNextButton.click()
}
async clickFinishCompatibilityQuestionButton() {
await expect(this.compatibilityQuestionFinishButton).toBeVisible()
await this.compatibilityQuestionFinishButton.click()
}
async clickCloseButton() {
await expect(this.closeButton).toBeInViewport()
await this.closeButton.click()
await expect(this.closeButton).toBeInViewport();
await this.closeButton.click();
};
async fillQuestionThoughts(thoughts: string | undefined) {
if (!thoughts) return
await expect(this.compatibilityQuestionThoughts).toBeVisible()
await this.compatibilityQuestionThoughts.fill(thoughts)
}
async clickStartAnsweringButton() {
await expect(this.startAnsweringButton).toBeVisible()
await this.startAnsweringButton.click()
}
await expect(this.startAnsweringButton).toBeVisible();
await this.startAnsweringButton.click();
};
async clickDoThisLaterButton() {
await expect(this.doThisLaterLink).toBeVisible()
await this.doThisLaterLink.click()
}
await expect(this.doThisLaterLink).toBeVisible();
await this.doThisLaterLink.click();
};
async clickShareButton() {
await expect(this.shareButton).toBeVisible()
await this.shareButton.click()
}
await expect(this.shareButton).toBeVisible();
await this.shareButton.click();
};
async clickEditProfileButton() {
await expect(this.editProfileButton).toBeVisible()
@@ -129,20 +264,20 @@ export class ProfilePage {
}
async selectOptionFromProfileDropdown(option: ProfileDropdownOptions) {
await expect(this.profileOptionsDropdown).toBeVisible()
await this.profileOptionsDropdown.click()
await expect(this.profileOptionsDropdown).toBeVisible();
await this.profileOptionsDropdown.click();
if (option === 'Public') {
await expect(this.listProfilePubliclyDropdownOption).toBeVisible()
await this.listProfilePubliclyDropdownOption.click()
await expect(this.listProfilePubliclyDropdownOption).toBeVisible();
await this.listProfilePubliclyDropdownOption.click();
} else if (option === 'Disable') {
await expect(this.disableProfileDropdownOption).toBeVisible()
await this.disableProfileDropdownOption.click()
await expect(this.disableProfileDropdownOption).toBeVisible();
await this.disableProfileDropdownOption.click();
} else if (option === 'Private') {
await expect(this.limitProfileToMembersDropdownOption).toBeVisible()
await this.limitProfileToMembersDropdownOption.click()
}
}
await expect(this.limitProfileToMembersDropdownOption).toBeVisible();
await this.limitProfileToMembersDropdownOption.click();
};
};
async verifyDisplayNameAndAge(displayName?: string, age?: string) {
await expect(this.displayNameAndAgeSection).toBeVisible()
@@ -159,7 +294,7 @@ export class ProfilePage {
) {
await expect(this.genderLocationHightInInchesSection).toBeVisible()
const textContent = await this.genderLocationHightInInchesSection.textContent()
if (gender) await expect(textContent?.toLowerCase()).toContain(gender.toLowerCase())
if (gender) await expect(textContent?.toLowerCase()).toContain(gender[0].toLowerCase())
if (location) await expect(textContent?.toLowerCase()).toContain(location.toLowerCase())
if (heightFeet) await expect(textContent?.toLowerCase()).toContain(heightFeet.toLowerCase())
if (heightInches) await expect(textContent?.toLowerCase()).toContain(heightInches.toLowerCase())
@@ -174,7 +309,7 @@ export class ProfilePage {
async verifyIntrestedInConnectingWith(gender?: string, minAge?: string, maxAge?: string) {
await expect(this.seekingAboutSection).toBeVisible()
const textContent = await this.seekingAboutSection.textContent()
if (gender) await expect(textContent?.toLowerCase()).toContain(gender.toLowerCase())
if (gender) await expect(textContent?.toLowerCase()).toContain(gender[0].toLowerCase())
if (minAge) await expect(textContent?.toLowerCase()).toContain(minAge.toLowerCase())
if (maxAge) await expect(textContent?.toLowerCase()).toContain(maxAge.toLowerCase())
}
@@ -182,15 +317,15 @@ export class ProfilePage {
async verifyRelationShipTypeAndInterest(type?: string, interest?: string) {
await expect(this.relationshipTypeAboutSection).toBeVisible()
const textContent = await this.relationshipTypeAboutSection.textContent()
if (type) await expect(textContent?.toLowerCase()).toContain(type.toLowerCase())
if (interest) await expect(textContent?.toLowerCase()).toContain(interest.toLowerCase())
if (type) await expect(textContent?.toLowerCase()).toContain(type[0].toLowerCase())
if (interest) await expect(textContent?.toLowerCase()).toContain(interest[0].toLowerCase())
}
async verifyRelationshipStatus(status: string | undefined) {
if (!status) return
await expect(this.relationshipStatusAboutSection).toBeVisible()
const textContent = await this.relationshipStatusAboutSection.textContent()
await expect(textContent?.toLowerCase()).toContain(status.toLowerCase())
await expect(textContent?.toLowerCase()).toContain(status[0].toLowerCase())
}
async verifyCurrentNumberOfKids(numberOfKids: string | undefined) {
@@ -238,7 +373,7 @@ export class ProfilePage {
await expect(this.educationAboutSection).toBeVisible()
const textContent = await this.educationAboutSection.textContent()
if (educationLevel)
await expect(textContent?.toLowerCase()).toContain(educationLevel.toLowerCase())
await expect(textContent?.toLowerCase()).toContain(educationLevel[0].toLowerCase())
if (university) await expect(textContent?.toLowerCase()).toContain(university.toLowerCase())
}
@@ -252,14 +387,14 @@ export class ProfilePage {
async verifyPoliticalBeliefs(belief?: string, details?: string) {
await expect(this.politicalAboutSection).toBeVisible()
const textContent = await this.politicalAboutSection.textContent()
if (belief) await expect(textContent?.toLowerCase()).toContain(belief.toLowerCase())
if (belief) await expect(textContent?.toLowerCase()).toContain(belief[0].toLowerCase())
if (details) await expect(textContent?.toLowerCase()).toContain(details.toLowerCase())
}
async verifyReligiousBeliefs(belief?: string, details?: string) {
await expect(this.relegiousAboutSection).toBeVisible()
const textContent = await this.relegiousAboutSection.textContent()
if (belief) await expect(textContent?.toLowerCase()).toContain(belief.toLowerCase())
if (belief) await expect(textContent?.toLowerCase()).toContain(belief[0].toLowerCase())
if (details) await expect(textContent?.toLowerCase()).toContain(details.toLowerCase())
}
@@ -284,7 +419,7 @@ export class ProfilePage {
if (!diet) return
await expect(this.dietAboutSection).toBeVisible()
const textContent = await this.dietAboutSection.textContent()
await expect(textContent?.toLowerCase()).toContain(diet.toLowerCase())
await expect(textContent?.toLowerCase()).toContain(diet[0].toLowerCase())
}
async verifySmoker(smoker: boolean | undefined) {
@@ -306,7 +441,7 @@ export class ProfilePage {
await expect(this.languagesAboutSection).toBeVisible()
const textContent = await this.languagesAboutSection.textContent()
for (let i = 0; i < languages.length; i++) {
await expect(textContent?.toLowerCase()).toContain(languages[i].toLowerCase())
await expect(textContent?.toLowerCase()).toContain(languages[i][0].toLowerCase())
}
}
@@ -324,4 +459,20 @@ export class ProfilePage {
await expect(this.bioSection).toBeVisible()
await expect(this.bioSection).toContainText(bio)
}
async verifyHeadline(headline: string | undefined) {
if (!headline) return
await expect(this.headlineSection).toBeVisible()
await expect(this.headlineSection).toContainText(headline)
}
async verifyKeywords(keywords: string | undefined) {
if (!keywords) return
console.log(this.keywordsSection.textContent());
const keywordsArr = keywords.split(", ")
await expect(this.keywordsSection).toBeVisible()
for (const word of keywordsArr) {
await expect(this.keywordsSection).toContainText(word)
}
}
}

View File

@@ -1,19 +1,19 @@
import {expect, Locator, Page} from '@playwright/test'
import {
ConnectionTypeKey,
DietKey,
EducationKey,
EthnicityKey,
LanguageKey,
ConnectionTypeTuple,
DietTuple,
EducationTuple,
EthnicityTuple,
LanguageTuple,
PersonalityKey,
PoliticalBeliefsKey,
RelationshipStatusKey,
RelationshipStyleKey,
ReligionKey,
} from 'common/choices'
PoliticalTuple,
RelationshipStatusTuple,
RelationshipStyleTuple,
ReligionTuple,
GenderTuple,
InterestedInGenderTuple,
} from '../../../../common/src/choices'
export type Gender = 'Woman' | 'Man' | 'Other'
export type InterestedIn = 'Women' | 'Men' | 'Other'
export type ChildrenExpectation =
| ['Strongly against', 0]
| ['Against', 1]
@@ -49,6 +49,9 @@ export class SignUpPage {
private readonly nextButton: Locator
private readonly bioField: Locator
private readonly locationField: Locator
// private readonly birthPlaceField: Locator
private readonly headlineField: Locator
private readonly keywordsField: Locator
private readonly ageField: Locator
private readonly feetHeightField: Locator
private readonly inchesHeightField: Locator
@@ -102,6 +105,8 @@ export class SignUpPage {
this.nextButton = page.getByRole('button', {name: 'Next', exact: true})
this.bioField = page.locator('.tiptap')
this.locationField = page.getByPlaceholder('Search city...')
this.headlineField = page.getByTestId('headline')
this.keywordsField = page.getByTestId('keywords')
this.ageField = page.getByPlaceholder('Age', {exact: true})
this.feetHeightField = page.getByTestId('height-feet')
this.inchesHeightField = page.getByTestId('height-inches')
@@ -172,10 +177,11 @@ export class SignUpPage {
await this.locationField.fill(location)
}
async chooseGender(gender: Gender | undefined) {
await expect(this.page.locator(`span:has-text("${gender}")`)).toBeVisible()
await this.page.locator(`span:has-text("${gender}")`).click()
await expect(this.page.locator(`span:has-text("${gender}")`)).toBeChecked()
async chooseGender(gender: GenderTuple | undefined) {
if (!gender) return
await expect(this.page.locator(`span:has-text("${gender[0]}")`)).toBeVisible()
await this.page.locator(`span:has-text("${gender[0]}")`).click()
await expect(this.page.locator(`span:has-text("${gender[0]}")`)).toBeChecked()
}
async fillAge(age: string | undefined) {
@@ -214,38 +220,40 @@ export class SignUpPage {
await this.centimetersHeightField.fill(centimeters)
}
async fillEthnicity(ethnicity: EthnicityKey | undefined) {
if (ethnicity === 'Other') {
async fillEthnicity(ethnicity: EthnicityTuple | undefined) {
if (!ethnicity) return
if (ethnicity[0] === 'Other') {
await expect(
this.page
.locator('label')
.filter({hasText: `${ethnicity}`})
.filter({hasText: `${ethnicity[0]}`})
.first(),
).toBeVisible()
await this.page
.locator('label')
.filter({hasText: `${ethnicity}`})
.filter({hasText: `${ethnicity[0]}`})
.first()
.click()
await expect(
this.page
.locator('label')
.filter({hasText: `${ethnicity}`})
.filter({hasText: `${ethnicity[0]}`})
.first(),
).toBeChecked()
} else {
await expect(this.page.getByText(`${ethnicity}`, {exact: true})).toBeVisible()
await this.page.getByText(`${ethnicity}`, {exact: true}).click()
await expect(this.page.getByText(`${ethnicity}`, {exact: true})).toBeChecked()
await expect(this.page.getByText(`${ethnicity[0]}`, {exact: true})).toBeVisible()
await this.page.getByText(`${ethnicity[0]}`, {exact: true}).click()
await expect(this.page.getByText(`${ethnicity[0]}`, {exact: true})).toBeChecked()
}
}
async fillInterestedInConnectingWith(interestedIn: InterestedIn | undefined) {
if (interestedIn === 'Men') {
async fillInterestedInConnectingWith(interestedIn: InterestedInGenderTuple | undefined) {
if (!interestedIn) return
if (interestedIn[0] === 'Men') {
await expect(this.interestedInMenCheckbox).toBeVisible()
await this.interestedInMenCheckbox.click()
await expect(this.interestedInMenCheckbox).toBeChecked()
} else if (interestedIn === 'Women') {
} else if (interestedIn[0] === 'Women') {
await expect(this.interestedInWomenCheckbox).toBeVisible()
await this.interestedInWomenCheckbox.click()
await expect(this.interestedInWomenCheckbox).toBeChecked()
@@ -266,22 +274,25 @@ export class SignUpPage {
}
}
async setConnectionType(type: ConnectionTypeKey | undefined) {
await expect(this.page.getByLabel(`${type}`, {exact: true})).toBeVisible()
await this.page.getByLabel(`${type}`, {exact: true}).click()
await expect(this.page.getByLabel(`${type}`, {exact: true})).toBeChecked()
async setConnectionType(type: ConnectionTypeTuple | undefined) {
if (!type) return
await expect(this.page.getByLabel(`${type[0]}`, {exact: true})).toBeVisible()
await this.page.getByLabel(`${type[0]}`, {exact: true}).click()
await expect(this.page.getByLabel(`${type[0]}`, {exact: true})).toBeChecked()
}
async setRelationshipStatus(status: RelationshipStatusKey | undefined) {
await expect(this.page.getByLabel(`${status}`, {exact: true})).toBeVisible()
await this.page.getByLabel(`${status}`, {exact: true}).click()
await expect(this.page.getByLabel(`${status}`, {exact: true})).toBeChecked()
async setRelationshipStatus(status: RelationshipStatusTuple | undefined) {
if (!status) return
await expect(this.page.getByLabel(`${status[0]}`, {exact: true})).toBeVisible()
await this.page.getByLabel(`${status[0]}`, {exact: true}).click()
await expect(this.page.getByLabel(`${status[0]}`, {exact: true})).toBeChecked()
}
async setRelationshipStyle(style: RelationshipStyleKey | undefined) {
await expect(this.page.getByLabel(`${style}`, {exact: true})).toBeVisible()
await this.page.getByLabel(`${style}`, {exact: true}).click()
await expect(this.page.getByLabel(`${style}`, {exact: true})).toBeChecked()
async setRelationshipStyle(style: RelationshipStyleTuple | undefined) {
if (!style) return
await expect(this.page.getByLabel(`${style[0]}`, {exact: true})).toBeVisible()
await this.page.getByLabel(`${style[0]}`, {exact: true}).click()
await expect(this.page.getByLabel(`${style[0]}`, {exact: true})).toBeChecked()
}
async fillCurrentNumberOfChildren(numberOfKids: string | undefined) {
@@ -358,10 +369,11 @@ export class SignUpPage {
}
}
async setHighestEducationLevel(education: EducationKey | undefined) {
await expect(this.page.getByText(`${education}`, {exact: true})).toBeVisible()
await this.page.getByText(`${education}`, {exact: true}).click()
await expect(this.page.getByText(`${education}`, {exact: true})).toBeChecked()
async setHighestEducationLevel(education: EducationTuple | undefined) {
if (!education) return
await expect(this.page.getByText(`${education[0]}`, {exact: true})).toBeVisible()
await this.page.getByText(`${education[0]}`, {exact: true}).click()
await expect(this.page.getByText(`${education[0]}`, {exact: true})).toBeChecked()
}
async fillUniversity(university: string | undefined) {
@@ -406,13 +418,13 @@ export class SignUpPage {
}
async setPoliticalBeliefs(
politicalBeliefs?: PoliticalBeliefsKey | undefined,
politicalBeliefs?: PoliticalTuple | undefined,
details?: string | undefined,
) {
if (politicalBeliefs) {
await expect(this.page.getByRole('checkbox', {name: `${politicalBeliefs}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${politicalBeliefs}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${politicalBeliefs}`})).toBeChecked()
await expect(this.page.getByRole('checkbox', {name: `${politicalBeliefs[0]}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${politicalBeliefs[0]}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${politicalBeliefs[0]}`})).toBeChecked()
}
if (details) {
@@ -421,32 +433,30 @@ export class SignUpPage {
}
}
async setReligiousBeliefs(
religiousBeliefs?: ReligionKey | undefined,
details?: string | undefined,
) {
if (religiousBeliefs && religiousBeliefs === 'Other') {
async setReligiousBeliefs(religiousBeliefs?: ReligionTuple | undefined, details?: string | undefined) {
if (!religiousBeliefs) return
if (religiousBeliefs[0] === 'Other') {
await expect(
this.page
.locator('label')
.filter({hasText: `${religiousBeliefs}`})
.filter({hasText: `${religiousBeliefs[0]}`})
.nth(3),
).toBeVisible()
await this.page
.locator('label')
.filter({hasText: `${religiousBeliefs}`})
.filter({hasText: `${religiousBeliefs[0]}`})
.nth(3)
.click()
await expect(
this.page
.locator('label')
.filter({hasText: `${religiousBeliefs}`})
.filter({hasText: `${religiousBeliefs[0]}`})
.nth(3),
).toBeChecked()
} else {
await expect(this.page.getByRole('checkbox', {name: `${religiousBeliefs}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${religiousBeliefs}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${religiousBeliefs}`})).toBeChecked()
await expect(this.page.getByRole('checkbox', {name: `${religiousBeliefs[0]}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${religiousBeliefs[0]}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${religiousBeliefs[0]}`})).toBeChecked()
}
if (details) {
@@ -616,15 +626,16 @@ export class SignUpPage {
}
}
async setDietType(dietType: DietKey | undefined) {
if (dietType === 'Other') {
async setDietType(dietType: DietTuple | undefined) {
if (!dietType) return
if (dietType[0] === 'Other') {
await expect(this.page.locator('label').filter({hasText: 'Other'}).nth(4)).toBeVisible()
await this.page.locator('label').filter({hasText: 'Other'}).nth(4).click()
await expect(this.page.locator('label').filter({hasText: 'Other'}).nth(4)).toBeChecked()
} else {
await expect(this.page.getByRole('checkbox', {name: `${dietType}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${dietType}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${dietType}`})).toBeChecked()
await expect(this.page.getByRole('checkbox', {name: `${dietType[0]}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${dietType[0]}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${dietType[0]}`})).toBeChecked()
}
}
@@ -646,13 +657,13 @@ export class SignUpPage {
await this.alcoholConsumedPerMonthField.fill(amount)
}
async setLanguages(language: LanguageKey[] | undefined) {
async setLanguages(language: LanguageTuple[] | undefined) {
if (!language || language.length === 0) return
await this.page.getByRole('checkbox', {name: `English`}).click()
await this.page.getByRole('checkbox', {name: `English`}).click();
for (let i = 0; i < language.length; i++) {
await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeVisible()
await this.page.getByRole('checkbox', {name: `${language[i]}`}).click()
await expect(this.page.getByRole('checkbox', {name: `${language[i]}`})).toBeChecked()
await expect(this.page.getByRole('checkbox', {name: `${language[i][0]}`})).toBeVisible();
await this.page.getByRole('checkbox', {name: `${language[i][0]}`}).click();
await expect(this.page.getByRole('checkbox', {name: `${language[i][0]}`})).toBeChecked();
}
}
@@ -690,4 +701,16 @@ export class SignUpPage {
await expect(this.saveButton).toBeVisible()
await this.saveButton.click()
}
async fillHeadline(headline: string | undefined) {
if (!headline) return
await expect(this.headlineField).toBeVisible()
await this.headlineField.fill(headline)
}
async fillKeywords(keywords: string | undefined) {
if (!keywords) return
await expect(this.keywordsField).toBeVisible()
await this.keywordsField.fill(keywords)
}
}

View File

@@ -29,8 +29,10 @@ test.describe('when given valid input', () => {
await signUpPage.fillHeight({
feet: testAccount.height?.feet,
inches: testAccount.height?.inches,
})
});
await signUpPage.fillEthnicity(testAccount.ethnicity_origin)
await signUpPage.fillHeadline(testAccount.headline)
await signUpPage.fillKeywords(testAccount.keywords)
await signUpPage.fillInterestedInConnectingWith(testAccount.interested_in)
await signUpPage.fillAgeRangeInterest(
testAccount.Interested_in_ages?.min,
@@ -51,13 +53,17 @@ test.describe('when given valid input', () => {
await signUpPage.setPoliticalBeliefs(
testAccount.beliefs?.political?.belief,
testAccount.beliefs?.political?.details,
)
);
await signUpPage.setReligiousBeliefs(
testAccount.beliefs?.religious?.belief,
testAccount.beliefs?.religious?.details,
)
await signUpPage.setPersonalityType(testAccount.personality_type)
await signUpPage.setOpennessPersonalityValue(testAccount.big_five_personality_traits?.openness)
await signUpPage.setAgreeablenessPersonalityValue(testAccount.big_five_personality_traits?.agreeableness)
await signUpPage.setConscientiousnessPersonalityValue(testAccount.big_five_personality_traits?.conscientiousness)
await signUpPage.setExtraversionPersonalityValue(testAccount.big_five_personality_traits?.extraversion)
await signUpPage.setNeuroticismPersonalityValue(testAccount.big_five_personality_traits?.neuroticism)
await signUpPage.setDietType(testAccount.diet)
await signUpPage.setIsSmoker(testAccount.is_smoker)
await signUpPage.fillAlcoholPerMonth(testAccount.alcohol_consumed_per_month)
@@ -67,29 +73,37 @@ test.describe('when given valid input', () => {
await signUpPage.clickNextButton()
await profilePage.clickCloseButton()
await onboardingPage.clickRefineProfileButton()
await profilePage.clickAnswerQuestionsButton()
const compatQuestionOne = await profilePage.answerCompatibilityQuestion(testAccount.compatibility)
await profilePage.clickNextCompatibilityQuestionButton()
await profilePage.clickSkipCompatibilityQuestionButton()
await profilePage.clickSkipCompatibilityQuestionButton()
await profilePage.clickSkipCompatibilityQuestionButton()
//Verify information is correct
await profilePage.verifyDisplayNameAndAge(testAccount.display_name, testAccount.age)
await profilePage.verifyHeadline(testAccount.headline)
await profilePage.verifyKeywords(testAccount.keywords)
await profilePage.verifyGenderLocationHeight(
testAccount.gender,
undefined,
testAccount.height?.feet,
testAccount.height?.inches,
)
);
await profilePage.verifyIntrestedInConnectingWith(
testAccount.interested_in,
testAccount.Interested_in_ages?.min,
testAccount.Interested_in_ages?.max,
)
);
await profilePage.verifyRelationShipTypeAndInterest(
testAccount.connection_type,
testAccount.relationship_style,
)
await profilePage.verifyRelationshipStatus(testAccount.relationship_status)
await profilePage.verifyCurrentNumberOfKids(testAccount.number_of_kids)
await profilePage.verifyWantChildrenExpectation(testAccount.children_expectation)
await profilePage.verifyInterests(testAccount.interests)
await profilePage.verifyCauses(testAccount.causes)
);
await profilePage.verifyRelationshipStatus(testAccount.relationship_status);
await profilePage.verifyCurrentNumberOfKids(testAccount.number_of_kids);
await profilePage.verifyWantChildrenExpectation(testAccount.children_expectation);
await profilePage.verifyInterests(testAccount.interests);
await profilePage.verifyCauses(testAccount.causes);
await profilePage.verifyEducationLevelAndUniversity(
testAccount.education_level,
testAccount.university,
@@ -99,7 +113,7 @@ test.describe('when given valid input', () => {
await profilePage.verifyPoliticalBeliefs(
testAccount.beliefs?.political?.belief,
testAccount.beliefs?.political?.details,
)
);
await profilePage.verifyReligiousBeliefs(
testAccount.beliefs?.religious?.belief,
testAccount.beliefs?.religious?.details,
@@ -112,39 +126,44 @@ test.describe('when given valid input', () => {
await profilePage.verifyLanguages(testAccount.languages)
await profilePage.verifySocialMedia(testAccount.social_media)
await profilePage.verifyBio(testAccount.bio)
await profilePage.verifyCompatibilityAnswers(compatQuestionOne)
//Verify Database Information
const dbInfo = await userInformationFromDb(testAccount)
// console.log(dbInfo.profile.bio_text);
console.log(dbInfo.profile);
await expect(dbInfo.user.name).toBe(testAccount.display_name)
await expect(dbInfo.user.username).toBe(testAccount.username)
await expect(dbInfo.profile.bio_text).toBe(testAccount.bio)
await expect(dbInfo.profile.gender).toEqual(`female`)
await expect(dbInfo.profile.gender).toEqual(testAccount.gender[1])
await expect(dbInfo.profile.headline).toEqual(testAccount.headline)
await expect(dbInfo.profile.keywords).toEqual(
expect.arrayContaining(testAccount.keywords?.split(", ") ?? [])
)
await expect(String(dbInfo.profile.age)).toEqual(testAccount.age)
await expect(dbInfo.profile.height_in_inches).toEqual(Number(testAccount.height?.feet) * 12)
await expect(dbInfo.profile.ethnicity).toContain('south_asian')
await expect(dbInfo.profile.pref_gender).toContain('male')
await expect(dbInfo.profile.ethnicity).toContain(testAccount.ethnicity_origin[1])
await expect(dbInfo.profile.pref_gender).toContain(testAccount.interested_in[1])
await expect(String(dbInfo.profile.pref_age_min)).toContain(testAccount.Interested_in_ages?.min)
await expect(String(dbInfo.profile.pref_age_max)).toContain(testAccount.Interested_in_ages?.max)
await expect(dbInfo.profile.pref_relation_styles).toContain(
`${testAccount.connection_type}`.toLowerCase(),
`${testAccount.connection_type[1]}`.toLowerCase(),
)
await expect(dbInfo.profile.relationship_status).toContain(`open`)
await expect(dbInfo.profile.pref_romantic_styles).toContain(`open`)
await expect(dbInfo.profile.relationship_status).toContain(testAccount.relationship_status[1])
await expect(dbInfo.profile.pref_romantic_styles).toContain(testAccount.relationship_style[1])
await expect(dbInfo.profile.has_kids).toEqual(Number(testAccount.number_of_kids))
await expect(dbInfo.profile.wants_kids_strength).toEqual(testAccount.children_expectation?.[1])
await expect(dbInfo.profile.education_level).toContain(
`${testAccount.education_level}`.toLowerCase(),
`${testAccount.education_level[1]}`.toLowerCase(),
)
await expect(dbInfo.profile.university).toContain(testAccount.university)
await expect(dbInfo.profile.occupation_title).toContain(testAccount.job_title)
await expect(dbInfo.profile.company).toContain(testAccount.company)
await expect(dbInfo.profile.political_beliefs).toContain('green')
await expect(dbInfo.profile.political_beliefs).toContain(testAccount.beliefs?.political?.belief[1])
await expect(dbInfo.profile.political_details).toContain(
testAccount.beliefs?.political?.details,
)
await expect(dbInfo.profile.religion).toContain('shinto')
await expect(dbInfo.profile.religion).toContain(testAccount.beliefs?.religious?.belief[1])
await expect(dbInfo.profile.religious_beliefs).toContain(
testAccount.beliefs?.religious?.details,
)
@@ -152,11 +171,23 @@ test.describe('when given valid input', () => {
await expect(dbInfo.profile.big5_openness).toEqual(
testAccount.big_five_personality_traits?.openness,
)
await expect(dbInfo.profile.diet).toContain(`${testAccount.diet}`.toLowerCase())
await expect(dbInfo.profile.big5_conscientiousness).toEqual(
testAccount.big_five_personality_traits?.conscientiousness,
)
await expect(dbInfo.profile.big5_extraversion).toEqual(
testAccount.big_five_personality_traits?.extraversion,
)
await expect(dbInfo.profile.big5_agreeableness).toEqual(
testAccount.big_five_personality_traits?.agreeableness,
)
await expect(dbInfo.profile.big5_neuroticism).toEqual(
testAccount.big_five_personality_traits?.neuroticism,
)
await expect(dbInfo.profile.diet).toContain(`${testAccount.diet[1]}`.toLowerCase())
await expect(dbInfo.profile.is_smoker).toEqual(testAccount.is_smoker)
await expect(dbInfo.profile.languages).toHaveLength(2)
await expect(dbInfo.profile.languages).toEqual(
expect.arrayContaining(testAccount.languages?.map((l) => l.toLowerCase()) ?? []),
expect.arrayContaining(testAccount.languages?.map(([_, l]) => l.toLowerCase()) ?? []),
)
await expect(String(dbInfo.profile.drinks_per_month)).toEqual(
testAccount.alcohol_consumed_per_month,
@@ -259,4 +290,4 @@ test.describe('when given valid input', () => {
test.describe('when an error occurs', () => {
test('placeholder', async () => {})
})
});

View File

@@ -1,46 +1,52 @@
import {faker} from '@faker-js/faker'
import {
ConnectionTypeKey,
DietKey,
EducationKey,
EthnicityKey,
LanguageKey,
ConnectionTypeTuple,
DietTuple,
EducationTuple,
EthnicityTuple,
LanguageTuple,
PersonalityKey,
PoliticalBeliefsKey,
RelationshipStatusKey,
RelationshipStyleKey,
ReligionKey,
PoliticalTuple,
RelationshipStatusTuple,
RelationshipStyleTuple,
ReligionTuple,
GenderTuple,
InterestedInGenderTuple,
} from 'common/choices'
import {
Causes,
ChildrenExpectation,
Gender,
InterestedIn,
Interests,
Platforms,
} from '../pages/signUpPage'
import { ImportanceTuple } from "web/components/answers/answer-compatibility-question-content";
export type OnboardingUser = {
email: string
password: string
display_name: string
username: string
current_location?: string
birth_location?: string
headline?: string
keywords?: string
bio?: string
gender?: Gender
gender?: GenderTuple
age?: string
height?: Height
ethnicity_origin?: EthnicityKey
interested_in?: InterestedIn
ethnicity_origin?: EthnicityTuple
interested_in?: InterestedInGenderTuple
Interested_in_ages?: InterestedInAges
connection_type?: ConnectionTypeKey
relationship_status?: RelationshipStatusKey
relationship_style?: RelationshipStyleKey
connection_type?: ConnectionTypeTuple
relationship_status?: RelationshipStatusTuple
relationship_style?: RelationshipStyleTuple
number_of_kids?: string
children_expectation?: ChildrenExpectation
interests?: (Interests | string)[]
causes?: (Causes | string)[]
education_level?: EducationKey
education_level?: EducationTuple
university?: string
job_title?: string
company?: string
@@ -48,11 +54,12 @@ export type OnboardingUser = {
beliefs?: BeliefDetails
personality_type?: PersonalityKey
big_five_personality_traits?: FiveBigPersonalityTraits
diet?: DietKey
diet?: DietTuple
is_smoker?: boolean
alcohol_consumed_per_month?: string
languages?: LanguageKey[]
languages?: LanguageTuple[]
social_media?: Socials[]
compatibility?: Compatibility
}
type Height = {
@@ -66,13 +73,19 @@ type InterestedInAges = {
max?: string
}
export type Compatibility = {
answer: string | null,
acceptableAnswers: (string | null)[],
importance: ImportanceTuple,
explanation: string
}
type BeliefDetails = {
political?: {
belief?: PoliticalBeliefsKey
belief?: PoliticalTuple
details?: string
}
religious?: {
belief?: ReligionKey
belief?: ReligionTuple
details?: string
}
}
@@ -100,7 +113,7 @@ export const onboarding: OnboardingConfig = {
faker_account: () => {
const id = crypto.randomUUID().slice(0, 6)
return {
email: `faker+${id}@test.com`,
email: `faker${id}@test.com`,
password: faker.internet.password(),
display_name: faker.internet.displayName(),
username: `user_${id}`,
@@ -111,60 +124,72 @@ export const onboarding: OnboardingConfig = {
const id = crypto.randomUUID().slice(0, 6)
return {
// Use a non-real TLD like @test.compass to make it obvious these are test accounts and prevent accidental emails
email: `onboarding+${id}@test.compass`,
email: `onboarding${id}@test.compass`,
password: 'CompassTest',
display_name: 'Compass Onboarding',
username: `TheGreatOnboarding_${id}`, // username max length is 25 (see /create-user)
keywords: 'Spicey noodles, Chocolate milk',
headline: 'I went out before dawn to hunt the mantis shrimp, the small bright terror that cracked shells like glass and watched me with colors no man could name. In the quiet water, I felt its strikes through the line as if the sea itself were warning me.',
bio: 'Born beneath twin moons, this wanderer maps forgotten roads, trades riddles for shelter, and keeps stories in glass bottles. Drawn to ancient libraries and glowing forests, they seek lost spells, quiet taverns, and adventures that rewrite fate. Their compass points to wonder. Ever onward. Always. Go',
gender: 'Woman',
gender: ['Woman', 'female'],
age: '25',
height: {
feet: '6',
inches: '0',
centimeters: '182.88',
},
ethnicity_origin: 'South/Southeast Asian',
interested_in: 'Men',
ethnicity_origin: ['South/Southeast Asian', 'south_asian'],
interested_in: ['Men', 'male'],
Interested_in_ages: {
min: '20',
max: '30',
},
connection_type: 'Relationship',
relationship_status: 'In open relationship',
relationship_style: 'Open Relationship',
connection_type: ['Relationship', 'relationship'],
relationship_status: ['In open relationship', 'open'],
relationship_style: ['Open Relationship', 'open'],
number_of_kids: '2',
children_expectation: ['Neutral', 2],
interests: ['Chess', 'Eating'],
causes: ['Animal Rights', 'Free Spotify'],
education_level: 'Bachelors',
education_level: ['Bachelors', 'bachelors'],
university: 'Open-Source University',
job_title: 'Unemployed',
company: 'Home',
work_area: ['Engineering', 'Academia'],
beliefs: {
political: {
belief: 'Green / Eco-Socialist',
belief: ['Green / Eco-Socialist', 'green'],
details: 'This will be details',
},
religious: {
belief: 'Shinto',
belief: ['Shinto', 'shinto'],
details: 'This will be details',
},
},
personality_type: 'ENFJ',
big_five_personality_traits: {
openness: 43,
agreeableness: 20,
conscientiousness: 32,
extraversion:63,
neuroticism:12
},
diet: 'Omnivore',
diet: ['Omnivore', 'omnivore'],
is_smoker: false,
alcohol_consumed_per_month: '4',
languages: ['Akan', 'Cebuano'],
languages: [['Akan', 'akan'], ['Cebuano', 'cebuano']],
social_media: [
{
platform: 'Bluesky',
urlOrUsername: 'TheGreatConnection',
},
],
compatibility: {
answer: '1',
acceptableAnswers: ['0', '2'],
importance: ["Important", 2],
explanation: 'This is my explanation one'
}
}
},
}
}

View File

@@ -31,7 +31,7 @@ export const IMPORTANCE_CHOICES = {
'Somewhat Important': 1,
Important: 2,
'Very Important': 3,
}
} as const
type ImportanceColorsType = {
[key: number]: string
@@ -160,7 +160,7 @@ export function AnswerCompatibilityQuestionContent(props: {
</span>
</Row>
)}
<div>{compatibilityQuestion.question}</div>
<div data-testid="compatibility-question">{compatibilityQuestion.question}</div>
{shortenedPopularity && (
<Row className="text-ink-500 select-none items-center text-sm">
<Tooltip
@@ -219,6 +219,7 @@ export function AnswerCompatibilityQuestionContent(props: {
</span>
<ExpandingInput
className={'w-full'}
data-testid="compatibility-question-thoughts"
rows={3}
value={answer.explanation ?? ''}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
@@ -286,6 +287,7 @@ export const SelectAnswer = (props: {
const {value, setValue, options} = props
return (
<RadioGroup
data-testid="compatibility-question-your-answer"
className={
'border-ink-300 text-ink-400 bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 text-sm shadow-sm'
}
@@ -296,6 +298,7 @@ export const SelectAnswer = (props: {
<RadioGroup.Option
key={i}
value={i}
data-testid={`compatibility-your-answer-${i}`}
className={({disabled}) =>
clsx(
disabled
@@ -322,6 +325,7 @@ export const MultiSelectAnswers = (props: {
return (
<Col
data-testid="compatibility-answers-you-accept"
className={
'border-ink-300 text-ink-400 bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 text-sm shadow-sm main-font'
}
@@ -329,6 +333,7 @@ export const MultiSelectAnswers = (props: {
{options.map((label, i) => (
<button
key={i}
data-testid={`compatibility-answers-you-accept-${i}`}
className={clsx(
values.includes(i)
? 'text-primary-700 bg-primary-100 hover:bg-primary-50'
@@ -345,3 +350,8 @@ export const MultiSelectAnswers = (props: {
</Col>
)
}
//Exported types for test files to use when referencing the keys of the choices objects
export type ImportanceTuple = {
[K in keyof typeof IMPORTANCE_CHOICES]: [K, (typeof IMPORTANCE_CHOICES)[K]]
}[keyof typeof IMPORTANCE_CHOICES]

View File

@@ -400,13 +400,17 @@ export function CompatibilityAnswerBlock(props: {
const isSkipped = answer && answer.importance == -1
return (
<Col
data-testid="profile-compatibility-section"
className={
'bg-canvas-0 flex-grow gap-4 whitespace-pre-line rounded-md px-3 py-2 leading-relaxed'
}
>
<Row className="text-ink-800 justify-between gap-1 font-semibold">
<Row
className="text-ink-800 justify-between gap-1 font-semibold"
data-testid="profile-compatibility-question"
>
{question.question}
<Row className="gap-4 font-normal">
<Row className="gap-4 font-normal" data-testid="profile-compatibility-importance">
{comparedProfile && isAnswered && (
<div className="hidden sm:block">
<CompatibilityDisplay
@@ -478,9 +482,14 @@ export function CompatibilityAnswerBlock(props: {
</Row>
</Row>
{answerText && (
<Row className="bg-canvas-100 w-fit gap-1 rounded px-2 py-1 text-sm">{answerText}</Row>
<Row
className="bg-canvas-100 w-fit gap-1 rounded px-2 py-1 text-sm"
data-testid="profile-compatibility-question-answer"
>
{answerText}
</Row>
)}
<Row className="px-2 -mt-4">
<Row className="px-2 -mt-4" data-testid="profile-compatibility-question-answer-explanation">
{answer?.explanation && <Linkify className="" text={answer.explanation} />}
</Row>
{distinctPreferredAnswersText.length > 0 && (
@@ -490,7 +499,10 @@ export function CompatibilityAnswerBlock(props: {
? t('answers.display.acceptable', 'Acceptable')
: t('answers.display.also_acceptable', 'Also acceptable')}
</div>
<Row className="flex-wrap gap-2 mt-0">
<Row
className="flex-wrap gap-2 mt-0"
data-testid="profile-compatibility-question-acceptable-answer"
>
{distinctPreferredAnswersText.map((text) => (
<Row key={text} className="bg-canvas-100 w-fit gap-1 rounded px-2 py-1 text-sm">
{text}

View File

@@ -52,6 +52,7 @@ export default function DropdownMenu(props: {
{({open, close}) => (
<>
<PopoverButton
data-testid="profile-compatibility-dropdown"
ref={refs.setReference}
className={clsx('text-ink-500 hover-bold flex items-center', buttonClass)}
onClick={(e: React.MouseEvent<HTMLButtonElement>) => e.stopPropagation()}

View File

@@ -11,6 +11,7 @@ export function LanguagePicker(props: {className?: string} = {}) {
return (
<select
id="locale-picker"
data-testid="sidebar-locale-picker"
value={locale}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => setLocale(e.target.value)}
className={clsx(

View File

@@ -9,6 +9,7 @@ export type Item = {
children?: React.ReactNode
trackingEventName?: string
href?: string
dataId?: string
onClick?: () => void
icon?: React.ComponentType<{className?: string}>
}
@@ -53,6 +54,7 @@ export function SidebarItem(props: {item: Item; currentPage?: string}) {
return (
<Link
href={item.href}
data-testid={`sidebar-${item.href?.replace('/', '')}`}
aria-current={isCurrentPage ? 'page' : undefined}
onClick={onClick}
className={sidebarClass}

View File

@@ -245,8 +245,12 @@ export default function ProfileHeader(props: {
refreshProfile()
}}
/>
{profile.headline && <div className="italic max-w-3xl px-4 py-3">{profile.headline}</div>}
<Row className={'px-4 gap-2 flex-wrap py-2'}>
{profile.headline && (
<div className="italic max-w-3xl px-4 py-3" data-testid="profile-headline">
{profile.headline}
</div>
)}
<Row className={'px-4 gap-2 flex-wrap py-2'} data-testid="profile-keywords">
{profile.keywords?.map(capitalize)?.map((tag, i) => (
<span
key={i}

View File

@@ -38,6 +38,7 @@ export function RadioToggleGroup(props: {
aria-label={choiceKey}
key={choiceKey}
value={choice}
data-testid={`compatibility-question-importance-${choice}`}
className={({disabled}) =>
clsx(
disabled ? 'cursor-not-allowed' : 'cursor-pointer ',