Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cypress testing suite for hidden features / bugs #543

Merged
merged 37 commits into from
Nov 9, 2021
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f26434c
Create new test file to test hidden cp features
willespencer Oct 15, 2021
2d41cfe
Programmatically delete testing onboarding data and run through initi…
willespencer Oct 15, 2021
0a7657f
Test walkthrough (and delete another firebase doc)
willespencer Oct 15, 2021
63e39d3
Confirm add semester buttons are mutually exclusive
willespencer Oct 15, 2021
93e7b9b
Test that CUReviews data is fetched
willespencer Oct 15, 2021
d1eb058
Swap order of login and delete Firestore data to fix permissions bug
willespencer Oct 16, 2021
1d304b9
Try more wait time to fix bug
willespencer Oct 18, 2021
3955c03
Fix lint and remove wait
willespencer Oct 18, 2021
68a1849
Try long polling
willespencer Oct 18, 2021
474fa6c
Add tests to click outside teleport/onboarding, move long polling
willespencer Oct 19, 2021
ef47a13
Add test to check mobile navbar z-index
willespencer Oct 19, 2021
083307f
Add console logging
willespencer Oct 26, 2021
c83ab4a
Bump cypress-firebase version, remove failing catches
willespencer Oct 26, 2021
ddabcec
Add a get check, change console log to cy log
willespencer Oct 26, 2021
a5ac626
Remove service account to see if old test succeeds
willespencer Oct 26, 2021
a582b15
Add back service account
willespencer Oct 26, 2021
3155048
Try modifying firestore inside test, after before, increase delay
willespencer Oct 26, 2021
aa22344
Try putting firestore calls inside login .then
willespencer Oct 26, 2021
e267faf
Merge branch 'master' into hidden-feature-unit-testing
willespencer Nov 4, 2021
383e91b
Merge branch 'master' into hidden-feature-unit-testing
willespencer Nov 4, 2021
fb78d92
Fix lint
willespencer Nov 4, 2021
12d1558
Write and test npm script to delete testing user collections
willespencer Nov 9, 2021
ec2177e
Add script to CI check, rename spec files to run in order
willespencer Nov 9, 2021
0b19794
Merge branch 'master' into hidden-feature-unit-testing
willespencer Nov 9, 2021
c3547fc
Move command to package.json
willespencer Nov 9, 2021
3c4831d
Add service account
willespencer Nov 9, 2021
1de3a1e
Clean up comments
willespencer Nov 9, 2021
1aea011
More cleanup
willespencer Nov 9, 2021
d3e810c
Use service account env variable
willespencer Nov 9, 2021
d8f730c
Use env variable in firebase admin config
willespencer Nov 9, 2021
ca159cd
JSON parse service account
willespencer Nov 9, 2021
5b4f6c7
Remove duplicated code
willespencer Nov 9, 2021
fc4044e
Add error console logs
willespencer Nov 9, 2021
792b70e
Now that service account secret refreshed, try old way again
willespencer Nov 9, 2021
26b18e7
Revert other changes made with script attempt
willespencer Nov 9, 2021
1f6bf9e
Fix lint
willespencer Nov 9, 2021
575bfe7
Move TEST_EMAIL to cypress.json
willespencer Nov 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 222 additions & 0 deletions cypress/integration/01-hidden-features.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/**
* A test file containing a number of tests on features and bugs that are often forgotten about when testing PRs.
* Can and should be expanded in the future.
* Note: This spec file must run on the CI before the others, as it will set the user's initial data after it is deleted by a script
*/

// Before running tests, delete Firestore data for the testing email (so the initial onboarding and walkthrough trigger)
// Then start on landing page, log in to firebase, and visits the dashboard
// Delete and log in occurs with TEST_UID and test email of the courseplan testing account using functions from the cypress-firebase package
before('Delete test user data, then visit site and log in', () => {
// log the user in
cy.visit('localhost:8080/login');
cy.login(Cypress.env('TEST_UID'));

const TEST_EMAIL = '[email protected]';

// delete test user's necessary collections to treat them as a new user
cy.callFirestore('delete', `user-onboarding-data/${TEST_EMAIL}`);
cy.callFirestore('delete', `user-semesters/${TEST_EMAIL}`);

// visit the site
cy.visit('localhost:8080');

// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(5000); // ensure the page has time to load
});

// Test to go through the onboarding flow
// Confirm that the next button cannot be clicked until all required fields have been filled out (as the user has no previous data)
it('Onboard a new user with all required fields', () => {
// confirm the next button is disabled and the error text is visible until all required fields filled out
cy.get('[data-cyId=onboarding-nextButton]').should('be.disabled');
cy.get('[data-cyId=onboarding-error]').scrollIntoView().should('be.visible');

// confirm that onboarding cannot be clicked outsideto close when creating a new user
cy.get('[data-cyId=onboarding]').clickOutside();
cy.get('[data-cyId=onboarding]').should('be.visible');

// set Graduation year to 2018
cy.get('[data-cyId=onboarding-dropdown]').eq(0).click();
cy.get('[data-cyId=onboarding-dropdownItem]').each($el => {
cy.wrap($el)
.invoke('text')
.then(text => {
if (text.includes('2018')) {
cy.wrap($el).click();
}
});
});
cy.get('[data-cyId=onboarding-nextButton]').should('be.disabled');
cy.get('[data-cyId=onboarding-error]').scrollIntoView().should('be.visible');

// set Graduation year to 2022
cy.get('[data-cyId=onboarding-dropdown]').eq(1).click();
cy.get('[data-cyId=onboarding-dropdownItem]').each($el => {
cy.wrap($el)
.invoke('text')
.then(text => {
if (text.includes('2022')) {
cy.wrap($el).click();
}
});
});
cy.get('[data-cyId=onboarding-nextButton]').should('be.disabled');
cy.get('[data-cyId=onboarding-error]').scrollIntoView().should('be.visible');

// set to Engineering college
cy.get('[data-cyId=onboarding-dropdown]').eq(2).click();
cy.get('[data-cyId=onboarding-dropdownItem]').each($el => {
cy.wrap($el)
.invoke('text')
.then(text => {
if (text.includes('Engineering')) {
cy.wrap($el).click();
}
});
});

// next button can be clicked and error not visible now that every field has been selected
cy.get('[data-cyId=onboarding-nextButton]').click();
cy.get('[data-cyId=onboarding-error]').should('not.exist');
cy.get('[data-cyId=onboarding-nextButton]').click();

// confirm 2018, 2022, and engineering are selected on the review screen
cy.get('[data-cyId=onboarding-entranceYear]').contains('2018');
cy.get('[data-cyId=onboarding-gradYear]').contains('2022');
cy.get('[data-cyId=onboarding-college]').contains('Engineering');
cy.get('[data-cyId=onboarding-finishButton]').click();
});

// Test to confirm that the new user walkthrough works as expected
// Click through the initial explanation, then the 4 following steps, and finally the finishing page
it('Click through the walkthrough tour', () => {
cy.get('[data-cyId=tour]').should('be.visible');
cy.get('[data-cyId=tour-startButton]').click();

// click through each step of the walkthrough, and confirm the tooltips are visible
// note that the introjs DOM elements come from the package, so cyID attributes cannot be used
cy.get('.tourStep1').should('be.visible');
cy.get('.introjs-nextbutton').click();

cy.get('.tourStep2').should('be.visible');
cy.get('.introjs-nextbutton').click();

cy.get('.tourStep3').should('be.visible');
cy.get('.introjs-nextbutton').click();

cy.get('.tourStep4').should('be.visible');
cy.get('.introjs-nextbutton').click();

// confirm the final page is visible and the tour can be finished
cy.get('[data-cyId=tour]').should('be.visible');
cy.get('[data-cyId=tour-startButton]').click();
});

// Test to confirm that only one "+New Semester" button shows up at once
// Due to front-end styling issues, there are two different buttons in different components
// Only one should be visible at a time (from semesterView if there are 0 semesters, from semester otherwise)
it('Test that only one semester button shows', () => {
// Delete each existing semester
const semesterMenus = '[data-cyId=semesterMenu]';
if (Cypress.$(semesterMenus).length > 0) {
// before deleting, confirm the semester button is the only version to exist
cy.get('[data-cyId=semester-addSemesterButton]').should('be.visible');
cy.get('[data-cyId=semesterView-addSemesterButton]').should('not.exist');

cy.get(semesterMenus).each($el => {
cy.wrap($el).click();
cy.get('[data-cyId=semesterMenu-delete]').click();
cy.get('[data-cyId=modal-button]').click();
});
}

// After all semesters deleted, confirm only the semesterView version is visible
cy.get('[data-cyId=semester-addSemesterButton]').should('not.exist');
cy.get('[data-cyId=semesterView-addSemesterButton]').should('be.visible');

// Add a semester back
cy.get('[data-cyId=semesterView-addSemesterButton]').click();

// click Fall
cy.get('[data-cyId=newSemester-seasonWrapper]').click();
cy.get('[data-cyId=newSemester-seasonItem]').first().click();

// click 2015
cy.get('[data-cyId=newSemester-yearWrapper]').click();
cy.get('[data-cyId=newSemester-yearItem]').first().click();

// add semester
cy.get('[data-cyId=modal-button]').click();

// Confirm only the semester version exists
cy.get('[data-cyId=semester-addSemesterButton]').should('be.visible');
cy.get('[data-cyId=semesterView-addSemesterButton]').should('not.exist');
});

// Test to confirm that CUReviews data is being loaded in for a sample course
// In the past, CUReviews data has stopped coming in and not been noticed since it is hidden in the bottom bar
it('Confirm CUReviews data exists', () => {
// open add modal and try to add CS 1110
cy.get('[data-cyId=semester-addCourse]').click();
cy.get('[data-cyId=newCourse-dropdown]').type('CS 1110');
cy.get('[data-cyId=newCourse-searchResult]').first().click();
cy.get('[data-cyId=modal-button]').click();

// open the bottom bar
cy.get('[data-cyId=semester-course]').click();

// confirm each CUReviews data value is not "N/A" - which occurs if data fetched incorrectly
cy.get('[data-cyId="CUReviews-overall')
.invoke('text')
.should(text => {
expect(text).not.to.eq('N/A');
});

cy.get('[data-cyId="CUReviews-difficulty')
.invoke('text')
.should(text => {
expect(text).not.to.eq('N/A');
});

cy.get('[data-cyId="CUReviews-workload')
.invoke('text')
.should(text => {
expect(text).not.to.eq('N/A');
});
});

// Test to confirm that teleport modals can be clicked outside of to close them
it('Click outside teleport modals', () => {
cy.get('[data-cyId=semester-addCourse]').click();
cy.get('[data-cyId=teleportModal]').should('be.visible');
cy.get('[data-cyId=teleportModal]').clickOutside();
cy.get('[data-cyId=teleportModal]').should('not.exist');
});

// Test to confirm that onboarding can be clicked outside (when editing)
it('Click outside onboarding modal', () => {
cy.get('[data-cyId=editProfile]').click();
cy.get('[data-cyId=onboarding]').should('be.visible');
cy.get('[data-cyId=onboarding]').clickOutside();
cy.get('[data-cyId=onboarding]').should('not.exist');
});

// Test to confirm the mobile menu shows up in front of the dashboard
// Also confirm onboarding and requirements can still be interacted with on mobile
it('Use mobile navbar', () => {
cy.viewport('samsung-s10'); // Set viewport to the dimensions of a Samsung S10

// confirm menu works
cy.get('[data-cyId=navbar-menuButton]').click();
cy.get('[data-cyId=navbar-menu]').should('be.visible');

// confirm onboarding works
cy.get('[data-cyId=navbar-editProfile]').click();
cy.get('[data-cyId=onboarding-cancel]').click();

// confirm requirements works
cy.get('[data-cyId=navbar-menuButton]').click();
cy.get('[data-cyId=navbar-viewRequirements]').click();
cy.get('[data-cyId=requirements-viewMore]').click();
});
File renamed without changes.
5 changes: 5 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,10 @@ const fbConfig = {

firebase.initializeApp(fbConfig);

Cypress.Commands.add(
'clickOutside',
() => cy.get('body').click(0, 0) // clicks at (0, 0)
);

// attach custom firebase commands to cypress from the cypress-firebase package
attachCustomCommands({ Cypress, cy, firebase });
5 changes: 5 additions & 0 deletions functions/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"logs": "firebase functions:log"
},
"dependencies": {
"cypress-firebase": "^2.0.0",
"esbuild": "^0.13.12",
"firebase-admin": "^9.12.0",
"firebase-functions": "^3.15.7"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"test": "jest",
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"cypress:e2e": "npm run build:dev && concurrently \"npm run serve:build\" \"wait-on http-get://localhost:8080 && npm run cypress:run\" --kill-others --success first"
"cypress:e2e": "npm run build:dev && concurrently \"npm run serve:build\" \"wait-on http-get://localhost:8080 && npm run cypress:run\" --kill-others --success first",
"cypress:set-data": "npm run ts-node -- src/requirements/admin/set-testing-account-data.ts"
},
"dependencies": {
"@cypress/vue": "^2.0.2",
Expand Down
12 changes: 9 additions & 3 deletions src/components/BottomBar/BottomBarCourseReview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
<div class="details-ratings">
<p class="details-ratings-title">
<span class="details-ratings-title-strong">Overall: </span>
<span class="details-ratings-strong">{{ CUROverallRating }}</span>
<span class="details-ratings-strong" data-cyId="CUReviews-overall">{{
CUROverallRating
}}</span>
</p>
<div class="progress rating">
<div
Expand All @@ -29,7 +31,9 @@
<div class="details-ratings">
<p class="details-ratings-title">
<span class="details-ratings-title-strong">Difficulty: </span>
<span class="details-ratings-strong"> {{ CURDifficulty }}</span>
<span class="details-ratings-strong" data-cyId="CUReviews-difficulty">
{{ CURDifficulty }}</span
>
</p>
<div class="progress rating">
<div
Expand All @@ -49,7 +53,9 @@
<div class="details-ratings">
<p class="details-ratings-title">
<span class="details-ratings-title-strong">Workload: </span>
<span class="details-ratings-strong">{{ CURWorkload }}</span>
<span class="details-ratings-strong" data-cyId="CUReviews-workload">{{
CURWorkload
}}</span>
</p>
<div class="progress rating">
<div
Expand Down
6 changes: 3 additions & 3 deletions src/components/Modals/Onboarding/Onboarding.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="onboarding" @click="checkClickOutside" ref="modalBackground">
<div class="onboarding" @click="checkClickOutside" ref="modalBackground" data-cyId="onboarding">
<div class="onboarding-main">
<div v-if="isEditingProfile" class="onboarding-cancel">
<button @click="cancel">
<button data-cyId="onboarding-cancel" @click="cancel">
<img
class="onboarding-cancel-icon"
src="@/assets/images/x.svg"
Expand Down Expand Up @@ -54,7 +54,7 @@
@setPage="setPage"
/>
</div>
<div class="onboarding-error" v-if="isError">
<div class="onboarding-error" data-cyId="onboarding-error" v-if="isError">
{{ errorText }}
</div>
<div class="onboarding-error" v-if="isInvalidMajorMinorGradError">
Expand Down
1 change: 1 addition & 0 deletions src/components/Modals/TeleportModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
}"
@click="closeOnClickOutside"
ref="modalBackground"
data-cyId="teleportModal"
>
<div
:class="['modal-content', contentClass, { 'modal-simple': isSimpleModal }]"
Expand Down
4 changes: 2 additions & 2 deletions src/components/Modals/TourWindow.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<teleport-modal content-class="content-tour" :isSimpleModal="true">
<div class="tour">
<div class="tour" data-cyId="tour">
<div class="intropage">
<div class="top">
<div class="dtiLogoWrapper">
Expand Down Expand Up @@ -40,7 +40,7 @@
<a href="mailto:[email protected]">[email protected]</a>.
</div>
</div>
<button class="startButton" @click="startTour()">
<button class="startButton" data-cyId="tour-startButton" @click="startTour()">
{{ buttonText }}
</button>
<button class="skipButton" @click="skipTour()">
Expand Down
11 changes: 8 additions & 3 deletions src/components/NavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<nav class="navbar">
<div
class="navbar-iconWrapper hamburger full-opacity-on-hover"
data-cyId="navbar-menuButton"
@click="menuOpen = !menuOpen"
></div>
<div class="navbar-top">
Expand All @@ -21,14 +22,18 @@
/>
</div>
<div v-if="menuOpen" class="navbar-menu-background-shadow" @click="editProfile" />
<div v-if="menuOpen" class="navbar-menu">
<button class="nav-mobile-button" @click="toggleRequirementsBar">
<div v-if="menuOpen" class="navbar-menu" data-cyId="navbar-menu">
<button
class="nav-mobile-button"
data-cyId="navbar-viewRequirements"
@click="toggleRequirementsBar"
>
<div class="navbar-iconWrapper requirements-bar" />
<span class="nav-mobile-button-text">
{{ isOpeningRequirements ? 'View Schedule' : 'View Requirements' }}
</span>
</button>
<button class="nav-mobile-button" @click="editProfile">
<button class="nav-mobile-button" data-cyId="navbar-editProfile" @click="editProfile">
<div class="navbar-iconWrapper profile-mobile-icon" />
<span class="nav-mobile-button-text">Edit Profile</span>
</button>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Requirements/RequirementSideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
:data-intro="getRequirementsTooltipText()"
data-disable-interaction="1"
data-step="1"
data-tooltipClass="tooltipCenter"
data-tooltipClass="tooltipCenter tourStep1"
>
<!-- loop through reqs array of req objects -->
<div
Expand All @@ -18,7 +18,7 @@
:data-intro="getCoursesTooltipText()"
data-disable-interaction="1"
data-step="2"
data-tooltipClass="tooltipCenter"
data-tooltipClass="tooltipCenter tourStep2"
>
<button
class="requirement-debugger-toggler"
Expand Down
Loading