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

Feature/issue 314 #319

Merged
merged 6 commits into from
Feb 11, 2023

Conversation

RascalTwo
Copy link
Collaborator

@RascalTwo RascalTwo commented Feb 7, 2023

Description

Implements front-end End-to-End testing using Cypress with code coverage results, additionally intercepting the Discord OAuth2 requests using nock to allow for testing of the entire login flow.

This is quite a large PR, but it contains mostly the new test files with a few additions to the express server and of course new package.json scripts.


The new packages are:

  • @cypress/code-coverage
    • Collects code coverage during Cypress tests.
  • @cypress/instrument-cra
  • cross-env
    • Enable cross-platform usage of environment variables in package.json scripts, which needed to set the server to run in test mode.
  • cypress
    • E2E Frontend testing tool.
  • eslint-plugin-cypress
    • ESLint plugin for Cypress, to allow for linting of Cypress test files.
  • nock
    • HTTP request intercepting library, used to intercept requests from Passport.js to Discord, making it possible to test the entire login flow.
  • nyc
    • Instruments code for code coverage collection, used by the server to collect code coverage results.
    • Additionally used to merge the server & client code coverage results into a single report.
    • Lastly used to generate an HTML & LCOV report of these results.
  • start-server-and-test
    • Allows the execution of a second command to wait for a resource to be available, in our case starts up the servers and waits for them to be ready before starting Cypress.

Newly added scripts include:

  • /package.json
    • coverage-concurrent
      • Similar to dev-concurrent, it starts up both the client and server in coverage mode - collecting code coverage results.
    • wait-for-coverage-concurrent
      • Starts up coverage-concurrent but via start-server-and-test, ensuring Cypress isn't opened until the servers are ready.
    • test-frontend
      • Starts up the servers and then runs the frontend tests, combining and generating coverage reports after.
    • dev-frontend-tests
      • Starts up the servers and then opens up the Cypress interactive GUI, allowing for the visual inspection of running tests.
  • /server/package.json
    • start:coverage
      • Start the server with nyc, collecting code coverage results.
  • /client/package.json
    • start:coverage
      • Start the react-scripts development server, but with @cypress/instrument-cra to instrument the code for code coverage collection.

There exists only one additional environment variable:

  • CYPRESS_NO_DELAYS
    • Will disable all necessary delays during testing if set.
    • The delays exist in the first place due to the desire to wait for animations to complete before interacting with the animated components.

The changes to the backend are mostly to allow for the mocking of the Discord OAuth2 requests, these have been encapsulated in a new file passport-discord-mocking.js, containing both the usage of nock to mock intercept the requests and the responses for each request endpoints.

Additional backend changes include the disabling of logging - both console.log()s and usage of morgan - when running the tests. This was done by using the standard NODE_ENV variable, and only enabling logging when NODE_ENV is not test.


It can be difficult to understand what the mocking has changed unless one knows how it was working before, so here is a diagram of the original flow between the frontend client, our Express server with Passport.js, and lastly the Discord API:

sequenceDiagram
    participant C as Client
    participant S as Server
    participant D as Discord
    autonumber
    note right of C: Click Login
    C ->>  S: /auth/discord
    activate S
    S ->>  D: /oauth2/authorize
    activate D
    deactivate S
    note right of S: Redirect
    D -->> S: /auth/discord/callback?code=CODE
    deactivate D
    activate S
    note left of D: Click Authorize
    S ->>  D: /api/oauth2/token
    activate D
    deactivate S
    D -->> S: Access & Refresh tokens
    activate S
    deactivate D
    S ->>  D: /api/users/@me
    deactivate S
    activate D
    D -->> S: Profile Info
    activate S
    deactivate D
    S ->>  D: /api/users/@me/guilds
    deactivate S
    activate D
    D -->> S: Joined Guilds array
    activate S
    deactivate D
    note over S: DiscordStrategy
    note left of S: Session Created
    S ->>  C: Homepage
    deactivate S
Loading

The most important part of this is that the difference implemented when the server is running in test mode is that instead of making requests to the real Discord API, the Passport.js requests will instead be intercepted by nock and mocked with the appropriate response - based on the hardcoded user codes.

Additionally, Cypress has one role to play in the testing, and that is to intercept the request made to the /auth/discord endpoint that would usually redirect the user to the Discord OAuth2 page, and instead redirect the user back to the Express server with a custom code that will be exchanged for the preset responses.

sequenceDiagram
    participant C as Client
    participant S as Server
    participant N as nock
    participant CY as Cypress
    autonumber
    note right of C: Click Login
    C ->>  S: /auth/discord
    activate S
    S ->>  CY: /oauth2/authorize
    deactivate S
    activate CY
    note right of S: Redirect
    CY -->> S: /auth/discord/callback?code=CUSTOM_CODE
    deactivate CY
    activate S
    S ->>  N: /api/oauth2/token
    deactivate S
    activate N
    N -->>  S: Mock Access & Refresh tokens
    deactivate N
    activate S
    S ->>  N: /api/users/@me/
    deactivate S
    activate N
    N -->>  S: Mock Profile Info
    deactivate N
    activate S
    S ->>  N: /api/users/@me/guilds
    deactivate S
    activate N
    N -->>  S: Mock Guilds array
    deactivate N
    activate S
    note over S: DiscordStrategy
    note left of S: Session Created
    S ->>  C: Homepage
    deactivate S
Loading

Now to move on to the actual new Cypress files:

  • cypress.config.js
    • Mostly the configuration for Cypress, including the base URL, some flags, and custom task functions.
    • clearDatabase
      • Clears the connected MongoDB database.
    • createEvent
      • Creates a new Event document.
    • generateObjectId
      • Generates a new ObjectId.
  • cypress
    • videos & screenshots
      • Videos & screenshots that are generated when running the tests, are ignored by git.
    • support
      • e2e.js
        • Imports the code-coverage logic, and custom commands, and adds a custom beforeEach hook to reset the database before each test and visit the homepage.
      • functions.js
        • Helper functions, mostly for dealing with dates.
      • commands.js
        • login
          • Login to the backend using the provided user code.
        • createOwnEvents
          • Create a number of events for the user code provided.
      • tgt.js
        • A collection of component-scoped actions & queries for Together as a whole.
        • This makes the actual tests more readable, additionally allowing for any updates to a single component in the future to be made in one place.
    • e2e
      • auth.cy.js
        • 100Dev members can log in and come back
        • Outsiders aren't logged in and are shown a rejection
        • All login/logout buttons work
      • landing.cy.js
        • Links
        • Hamburger menu
      • calendar.cy.js
        • Links
        • Accessible via the calendar button
        • Guest users can't create events
        • Current day is highlighted
        • Month is changeable via buttons & scrolling
        • Only shows events for the current month
      • view-event-modal.cy.js
        • Event models are shown when clicking on an event
        • Non-authors of events can't see the delete buttons
        • Authors can delete individual & all recurring events
      • create-event-form.cy.js
        • The event creation form is accessible and prevents any invalid submissions
        • The expected network requests are made to the backend
        • Created events are instantly shown on the calendar

I did discover a number of unused code segments while writing the tests, while some may have future use I'll list them just in case:

Additionally, I ran across two bugs while writing the tests:

  • Guests can not view the event modal - already documented in Modals not displaying for unauthenticated guest users/visitors. #279
    • Left an integration into the visibility test that may pass it in view-event-modal.cy.js depending on implementation.
  • Non-recurring events have the Delete All Events button, which currently only throws an error.
    • As the desired behavior is unknown - whether the button should not exist on non-recurring events, or if it should behave the same as the Delete Specific Event button - I left nothing in the tests relating to it.
    • The underlying issue is that non-recurring events have a groupId of null, hence the button results in a DELETE request to /events/deleteAllEvents/null.
  • More of an inconvenience than a bug that the modal containing the UserForm for creating events can only be exited by clicking the backdrop - it has no explicit close button.

Type of change

Please select everything applicable. Please, do not delete any lines.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
    • Describing at minimum the new package.json scripts test-frontend and dev-frontend-tests

Issue

Checklist

  • This PR is up to date with the development branch, and merge conflicts have been resolved
  • I have executed npm run lint and resolved any outstanding errors. Most issues can be solved by executing npm run format
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented on my code, particularly in hard-to-understand areas
  • My changes generate no new warnings

Update eslint config
Update gitignore
Add testing development mongo path
Cypress wasn't properly listening to the CYPRESS_NO_DELAYS environment variable to disable the animations waits
@isaaclee12
Copy link
Contributor

This dude is cracked I swear

@Caleb-Cohen
Copy link
Member

This dude is cracked I swear

Just Rascal being Rascal.

@Caleb-Cohen Caleb-Cohen merged commit c2e64c4 into Together-100Devs:development Feb 11, 2023
Caleb-Cohen added a commit that referenced this pull request Feb 18, 2023
* Added testing to pull request template

* Feature/issue 314 (#319)

* Install Cypress & needed packages

Update eslint config
Update gitignore
Add testing development mongo path

* Add nock Passport.js Discord request interception

* Add Cypress tests

* Disable server logging when testing

* Fix delay-toggling environment variable

Cypress wasn't properly listening to the CYPRESS_NO_DELAYS environment variable to disable the animations waits

* added modulus to getHoursAndMinutes

---------

Co-authored-by: Caleb Cohen <CalebCohen@hotmail.com>

* starting workflow for actions

* typo within review pull request

* add environment dev to workflow

* workflow changes

* lint fixes (#324)

* Actions timeout (#326)

* Add timeout to GitHub actions

GitHub action workflows should be limited so minutes aren't wasted if it hangs and bugs can be caught earlier. If 30 minutes isn't enough, it can be increased later on

* change timeout to 10 minutes

* Modified app metadata to "Together is a scheduling and collaboration … (#325)

* Modified app metadata to "Together is a scheduling and collaboration tool built for and  by 100Devs community for creating, discovering and keeping track of events on discord."

* Deleted the extra space.

* Server tests. #288 (#289)

* install jest and supertest

* separate app and server into different files

* add jest coverage folder to gitignore

* allow the use of mock user in test environment

* change validateBody to be a sync function

* add 'use strict', fix variable declarations

* extract constants

* remove console logs

* add mock user to db

* refactor, fix validation bugs in createEventSchema

* test httpError

* test validateObjectId

* test validateBody

* refactor unit tests

* export STRING_MAX_LENGTH to be used in tests

* fix dotenv path to work in tests

* modify mock request

* test routes

* refactor maxEvents middleware

* add tests for maxEvents

* allow event end time (not date) to be before start time

* test create event with valid data

* timezone bug fix: add offset to days

* test createEventArray

* create date range with Date  instead of datefns lib

* test createEventsArray in JST timezone

* refactor createEventsArray and tests

* fix test JST time

* use Temporal to work with dates

* fix event duration using Temporal

* test cases for createEventsArray

* test validateBody

* fix acceptance tests

* change hardcoded timezone to machine timezone

* update test script

* remove irrelevant test (maxEvents)

* update front-end test

* add script to run all tests together

* add route tests

* added formidable, jsbi, moved jest and supertest to dev dependencies

---------

Co-authored-by: Caleb Cohen <CalebCohen@hotmail.com>

* Fix guest modal and and updated test (#327)

* Fix guest modal and and updated test

* author changes and lint fix

* Make time-asserting code locale-based

---------

Co-authored-by: Rascal_Two <therealrascaltwo@gmail.com>

* Removed delete all button from non-recurring events (#332)

* Removed delete all button from non-recurring events

* Removed console.log from file

* Feature/issue 305 (#339)

* changed description section input element to textarea element. This change added multi-line functionality and a larger textbox size.

* In the input object, I changed the input element text to textarea. Cypress now reflects the changes made in the codebase for proper testing.

* Created a close button, in UserForm.js (#333)

---------

Co-authored-by: Rascal Two <therealrascaltwo@gmail.com>
Co-authored-by: Jacob Asper <jacobasper191@gmail.com>
Co-authored-by: uaravindshenoy <75222342+uaravindshenoy@users.noreply.github.com>
Co-authored-by: Roman Stetsyk <25715951+romanstetsyk@users.noreply.github.com>
Co-authored-by: Lalysi <75863568+lalysi@users.noreply.github.com>
Co-authored-by: Mike Jakuszewski <114702999+MikeJakuszewski@users.noreply.github.com>
Co-authored-by: Jae Salaski <hello@jsalaski.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement Front-End Test Suite
3 participants