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

refactor: extract login from Cypress tests #981

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

gminetoma
Copy link
Contributor

@gminetoma gminetoma commented Jan 24, 2025

Resolves #797

🔧 What changed

✨ Linting

Fixed Cypress linting

🧪 Test Environment

Added Yarn support for .env.test to securely manage environment
variables required for testing. The .env.test file includes:

  • AUTH0_DOMAIN
  • AUTH0_USERNAME
  • AUTH0_PASSWORD

These variables are critical for the Auth0 login process. To ensure
security, only authorized individuals will have access to the
.env.test file, and it has been added to .gitignore to prevent
accidental commits of sensitive information.

🤖 Cypress

Add Cypress cy.login() custom command

  • Introduce an utils file with the following functions:
    • auth0Login: Handles the Auth0 login routine
    • hasOperation: Checks the request query for a specific operation
    • aliasQuery: Adds an alias for an operation and stubs it
  • Change file extensions to .ts
  • Add Cypress plugin types to tsconfig.json
  • Import Cypress plugins in e2e.ts

This introduces a custom cy.login() command for Cypress that
uses the Auth0 login routine to create a login session. This optimizes
testing by reducing the need for repetitive logins during tests.

Additionally, it adds utility functions to simplify the manipulation of
GraphQL requests. Furthermore, Cypress plugins are now imported in a
centralized e2e.ts file, eliminating the need to import them
individually in each test file.

📝 Cypress Tests

Simplify login process and enhance cypress.intercept usage

  • Remove unnecessary plugin imports
  • Directly import JSON fake data
  • Use the new cy.login() command
  • Separate each test suite into a different spec file

This refactor streamlines the login process for tests, improving both
speed and efficiency. Instead of using fixtures for fake data, JSON
files are now directly imported, as fixtures are unnecessary due to how
GraphQL requests are manipulated.

Cypress plugin imports have been centralized in the support file,
removing the need for redundant imports in individual test files.

Additionally, test suites have been separated into different spec files
for better organization and maintainability.

🎬 GitHub Actions

Updated the configuration to ensure GitHub Actions runs E2E tests
using our custom command (yarn test:e2e) and GitHub secrets.
This guarantees that the tests follow our defined configurations,
ensuring consistency between local development and CI environments.

📑 References:

https://www.npmjs.com/package/eslint-plugin-cypress
https://www.npmjs.com/package/cypress-plugin-tab
https://docs.cypress.io/app/guides/network-requests#Working-with-GraphQL
https://docs.cypress.io/app/guides/authentication-testing/auth0-authentication
https://github.com/dmtrKovalenko/cypress-real-events#readme
https://github.com/cypress-io/github-action

@gminetoma gminetoma linked an issue Jan 24, 2025 that may be closed by this pull request
3 tasks
Copy link

netlify bot commented Jan 24, 2025

Deploy Preview for findadoc ready!

Name Link
🔨 Latest commit a54a4ec
🔍 Latest deploy log https://app.netlify.com/sites/findadoc/deploys/67a24917fbe5810008198cfc
😎 Deploy Preview https://deploy-preview-981--findadoc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@gminetoma gminetoma changed the title Refactor/cypress login refactor: extract login from Cypress tests Jan 24, 2025
@gminetoma gminetoma force-pushed the refactor/cypress-login branch 2 times, most recently from 263c85e to fe4eeaf Compare January 24, 2025 07:05
@gminetoma gminetoma self-assigned this Jan 24, 2025
@gminetoma gminetoma added code quality testing cypress Tests related to user interface interactions using Cypress. labels Jan 24, 2025
@gminetoma gminetoma force-pushed the refactor/cypress-login branch 17 times, most recently from 032c510 to 6b82aff Compare January 24, 2025 16:26
@gminetoma
Copy link
Contributor Author

@NabbeunNabi

@gminetoma gminetoma requested a review from NabbeunNabi January 25, 2025 04:52
.env.test Outdated Show resolved Hide resolved
Copy link
Contributor

@NabbeunNabi NabbeunNabi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gminetoma great work. Just a few initial questions

.yarnrc.yml Outdated
@@ -5,3 +5,6 @@ enableGlobalCache: false
nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.4.0.cjs

injectEnvironmentFiles:
- .env.test?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be changed to github secrets for the CI/CD?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way it is now (with the env file and the Cypress action config) is working because yarn is loading the env variables. This should be changed if don't have the env file anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like there's a better option here like importing through the yarn command in package.json or through the yaml file 🤔

Copy link
Contributor Author

@gminetoma gminetoma Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ermish

We could install a package like dotenv or cross-env to set the env file in a yarn command.

I think we can't use the yaml file because we still want to load the variables during the development while creating moderation tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are fine to add 👍
we're actively using both of them in our projects already

@gminetoma gminetoma force-pushed the refactor/cypress-login branch from 480d9c7 to f50356c Compare January 25, 2025 12:43
@gminetoma gminetoma requested a review from NabbeunNabi January 25, 2025 12:55
@gminetoma gminetoma marked this pull request as ready for review January 25, 2025 12:56
gminetoma added a commit that referenced this pull request Jan 27, 2025
This issue is solved here: [#981](#981)
@@ -94,32 +94,12 @@ export default withNuxt(
'vue/html-indent': ['error', 4]
}
},
// Linting for tests (cypress + pinia)
// Linting for Cypress (https://www.npmjs.com/package/eslint-plugin-cypress)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to keep support for our pinia tests so we should split this config section into two then. One for cypress and one for pinia files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, for Pinia tests, we are using Vitest. I'm already addressing its rules here:
Issues: #982
Commit: commit

cypress: pluginCypress
},
files: ['test/cypress/**/*'],
...pluginCypress.configs.recommended,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you check that we actually want all the rules from here? I haven't checked cypress recommended, but it's pretty common they can be more annoying than helpful.
I'm ok with it if we check they make sense first 🙏

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm on this one

Copy link
Contributor Author

@gminetoma gminetoma Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not using any rules for Cypress right now. We are using the plugin only for the globals. We are overriding the rules as you can see here.

// Linting for Cypress (https://www.npmjs.com/package/eslint-plugin-cypress)
{
    files: ['test/cypress/**/*'],
    ...pluginCypress.configs.recommended,
    rules: {
        'cypress/no-unnecessary-waiting': 'off'
    }
}

I would recommend activating the rules since they follow Cypress best practices. I tested the recommended rules, and we will have a lot to refactor if we decide to activate them.

Here are the plugin's recommended options:

Object.assign(plugin.configs, {
  recommended: {
    name: 'cypress/recommended',
    plugins: {
      cypress: plugin
    },
    rules: {
      'cypress/no-assigning-return-values': 'error',
      'cypress/no-unnecessary-waiting': 'error',
      'cypress/no-async-tests': 'error',
      'cypress/unsafe-to-chain-command': 'error',
    },
    languageOptions: {
      globals:
        commonGlobals,
      ...commonLanguageOptions
    }
  }
})

Cypress recommended rules
Cypress best practices

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should activate them 👍 let's do it in a separate PR though with the corresponding changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking it would add the rules in addition to ours but I realized it's the config section and not the rules set

Copy link
Contributor Author

@gminetoma gminetoma Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ermish

Do you want me to move all the linting part to another PR? Should I remove the commit?

Copy link
Contributor

@ermish ermish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments

}

// https://docs.cypress.io/app/guides/network-requests#Working-with-GraphQL
export const aliasQuery = (req: IncomingHttpRequest, operation: string, responseBody: unknown) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for? I can't tell from quickly reading it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set the alias for a request based on the operation name. After setting it, we can use cy.wait(@{alias}).

I'm following the Cypress documentation for working with GraphQL.

})
}

export const hasOperation = (req: IncomingHttpRequest, operation) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if the GraphQL operation is included in the request body

}

// https://docs.cypress.io/api/commands/intercept#Interception-lifecycle
export const requestHandler = (req: IncomingHttpRequest) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is only doing one purpose of clearing the cache, that would be a better function name here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const preventRequestCache = (req: IncomingHttpRequest) => {
    req.on('before:response', res => {
        // force all API responses to not be cached
        res.headers['cache-control'] = 'no-store'
    })
}

isInViewport(args?: string): Chainable<JQuery<HTMLElement>>
isNotInViewport(args?: string): Chainable<JQuery<HTMLElement>>
}
declare namespace Cypress{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this type come from cypress types or an @types/cypress library?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using the Cypress namespace, and we don't have @types/cypress. We are extending the Cypress namespace with our custom command.

Types for custom commands

Sorry, I think I didn't understand your question. Could you elaborate more, please?

autoEnd: false
})

log.snapshot('before')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of "before" and "after", can be more explicit like
"connecting to auth0"
And
"Successfully logged in"

Copy link
Contributor Author

@gminetoma gminetoma Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if you meant to ask this, but those snapshots are only for debugging.

To me, it doesn’t make much sense to do it this way. 'Before' the auth and 'After' makes more sense to me.

If this is your intention, I'll do it your way.

image

cypress: pluginCypress
},
files: ['test/cypress/**/*'],
...pluginCypress.configs.recommended,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm on this one

@gminetoma gminetoma force-pushed the refactor/cypress-login branch from e7d00a6 to a3674fc Compare February 3, 2025 09:23
Copy link

socket-security bot commented Feb 3, 2025

👍 Dependency issues cleared. Learn more about Socket for GitHub ↗︎

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report↗︎

@gminetoma gminetoma requested a review from ermish February 3, 2025 09:27
@gminetoma gminetoma force-pushed the refactor/cypress-login branch from b4d5b4c to 8c09bd3 Compare February 3, 2025 09:32
@gminetoma gminetoma removed the request for review from NabbeunNabi February 3, 2025 10:26
@gminetoma gminetoma force-pushed the refactor/cypress-login branch 2 times, most recently from 9bc8279 to c432760 Compare February 3, 2025 10:29
gminetoma and others added 11 commits February 5, 2025 01:26
- Set the correct Cypress path
- Set eslint-plugin-cypress config to recommended

Reference:
https://www.npmjs.com/package/eslint-plugin-cypress
- Add Cypress environment variables in `cypress.config`
- Remove unnecessary support folder configuration
- Change e2e support file extension to `.ts`
- Update `.gitignore` to ignore `.env.test`

Added Yarn support for `.env.test` to securely manage environment
variables required for testing. The `.env.test` file includes:
- `AUTH0_DOMAIN`
- `AUTH0_USERNAME`
- `AUTH0_PASSWORD`

These variables are critical for the Auth0 login process. To ensure
security, only authorized individuals will have access to the
`.env.test` file, and it has been added to `.gitignore` to prevent
accidental commits of sensitive information.
- Introduce a utils file with the following functions:
  - `auth0Login`: Handles the Auth0 login routine
  - `hasOperation`: Checks the request query for a specific operation
  - `aliasQuery`: Adds an alias for an operation and stubs it
- Change file extensions to `.ts`
- Add Cypress plugin types to `tsconfig.json`
- Import Cypress plugins in `e2e.ts`

This commit introduces a custom `cy.login()` command for Cypress that
uses the Auth0 login routine to create a login session. This optimizes
testing by reducing the need for repetitive logins during tests.

Additionally, it adds utility functions to simplify the manipulation of
GraphQL requests. Furthermore, Cypress plugins are now imported in a
centralized `e2e.ts` file, eliminating the need to import them
individually in each test file.

References:
https://docs.cypress.io/app/guides/network-requests#Working-with-GraphQL
https://docs.cypress.io/app/guides/authentication-testing/auth0-authentication
https://github.com/dmtrKovalenko/cypress-real-events#readme
https://www.npmjs.com/package/cypress-plugin-tab
- Remove unnecessary plugin imports
- Directly import JSON fake data
- Use the new `cy.login()` command
- Separate each test suite into a different spec file

This refactor streamlines the login process for tests, improving both
speed and efficiency. Instead of using fixtures for fake data, JSON
files are now directly imported, as fixtures are unnecessary due to how
GraphQL requests are manipulated.

Cypress plugin imports have been centralized in the support file,
removing the need for redundant imports in individual test files.

Additionally, test suites have been separated into different spec files
for better organization and maintainability.
- Remove the `--record` and `--key` parameters

Updated the e2e tests to use the default browser instead of Chrome.
Chrome requires manual permissions for certain actions, such as copying
text, which can disrupt automated testing. This change ensures a smoother and more reliable testing process.

Additionally, removing the `--record` parameter restores the runner UI
in screenshots. This is essential for debugging issues in CLI mode, as
the UI provides critical context for test failures.
Updated the configuration to ensure GitHub Actions runs e2e tests using
our custom command (`yarn test:e2e`). This guarantees that the tests use
our defined configurations, providing consistency between local
development and CI environments.
- Add `dotenv-cli` to load environment variables from `.env` files
- Add a new package script:
  - `test:e2e:open` - Opens the Cypress UI with `.env.test` variables

Introduced `dotenv-cli` to simplify loading environment variables for tests. Due to `dotenv-cli` loading the env variables only after `--`, additional scripts were added to ensure proper loading.

- Use `yarn test:e2e` and `yarn test:e2e:open` for running tests.
- Other scripts are included only for debugging and running Cypress commands.

- These commands will not work without the `.env.test` file.
@gminetoma gminetoma force-pushed the refactor/cypress-login branch from c432760 to 989417a Compare February 4, 2025 16:31
Issue appeared after merging [#989](#989)
@gminetoma gminetoma force-pushed the refactor/cypress-login branch from 819a841 to a54a4ec Compare February 4, 2025 17:06
Copy link

Report too large to display inline

View full report↗︎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code quality cypress Tests related to user interface interactions using Cypress. testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor the login on moderation into the cypress.config.ts
3 participants