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

fix: issue with compilation failures in component testing #21599

Merged
merged 34 commits into from
May 25, 2022

Conversation

ryanthemanuel
Copy link
Collaborator

@ryanthemanuel ryanthemanuel commented May 23, 2022

User facing changelog

Component specs with webpack compilation errors no longer exit the server process in run mode, their results get sent to the dashboard, and the exit code is specified properly. Component specs with vite compilation errors no longer hang in run or open mode.

Additional details

Each framework handles compilation and linting errors slightly differnently. This PR focuses on compilation errors. An explanation of the current, proposed interim (on this PR), and proposed ideal states can be found in this google doc

Compilation Errors when using the Webpack Framework

The main problem with this scenario is that we currently emit a webpack failure on compilation errors and in one of the handlers, we immediately exit the server process. This doesn't allow us to return the appropriate status codes, report to the dashboard appropriately, or continue running specs that don't have compilation errors.

The interim solution to this problem is to no longer exit the process. Webpack automatically injects the compilation error into the problematic module and Cypress's generic error mechanism handles this correctly.

Longer term, we could investigate displaying a custom error for this scenario rather than the generic uncaught exception message.

Compilation Errors when using the Vite Framework

The main problem with this scenario is that esbuild errors out during the optimization process and assets are not generated.
The interim solution to this problem is to add an esbuild plugin that changes the errors to warnings. Vite will then not end up generating an asset for the bad asset and we will get a 500 error whenever the asset is loaded. This will end up getting this scenario to an acceptable state for both open and run mode, however it won't allow for the compilation error message to be displayed to the user. Instead it will be a more generic error.

In the long run, we will try and make the error more user friendly and specific. Some investigation will be needed to figure out:

  • How to inject the compilation error in the problematic asset in such a way that Cypress can catch it and display it to the user in a non-generic way
  • Can this be done with the vite-dev-server? Or do we need to try and create a static compilation in run mode? Initial investigation into this seemed to cause a stall in starting testing, so we will need to watch performance. If we do this, how do we solve open mode?

How has the user experience changed?

PR Tasks

  • Have tests been added/updated?
  • [na] Has the original issue (or this PR, if no issue exists) been tagged with a release in ZenHub? (user-facing changes only)
  • [na] Has a PR for user-facing changes been opened in cypress-documentation?
  • [na] Have API changes been updated in the type definitions?
  • [na] Have new configuration options been added to the cypress.schema.json?

@cypress-bot
Copy link
Contributor

cypress-bot bot commented May 23, 2022

Thanks for taking the time to open a PR!

@cypress
Copy link

cypress bot commented May 23, 2022



Test summary

9746 0 120 0Flakiness 2


Run details

Project cypress
Status Passed
Commit c9a21a7
Started May 25, 2022 9:23 PM
Ended May 25, 2022 9:42 PM
Duration 19:31 💡
OS Linux Debian - 10.11
Browser Multiple

View run in Cypress Dashboard ➡️


Flakiness

e2e/origin/commands/actions.cy.ts Flakiness
1 cy.origin actions > #consoleProps > .selectFile()
cypress/proxy-logging.cy.ts Flakiness
1 Proxy Logging > request logging > xhr log has response body/status code when xhr response is logged second

This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard

@ryanthemanuel ryanthemanuel marked this pull request as ready for review May 24, 2022 01:31
@ryanthemanuel ryanthemanuel requested review from a team as code owners May 24, 2022 01:31
@ryanthemanuel ryanthemanuel requested review from jennifer-shehane and tgriesser and removed request for a team May 24, 2022 01:31
@ryanthemanuel ryanthemanuel requested review from tbiethman and removed request for a team and jennifer-shehane May 24, 2022 13:54
@ZachJW34 ZachJW34 changed the base branch from 10.0-release to develop May 25, 2022 14:12
@ryanthemanuel ryanthemanuel requested a review from BlueWinds May 25, 2022 14:40
Copy link
Contributor

@ZachJW34 ZachJW34 left a comment

Choose a reason for hiding this comment

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

One change for the merging of the webpackConfig, the rest are minor. Tested and it works great, HUGE improvement

incremental: true,
plugins: [
{
name: 'esbuild-plugin',
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we change this to cypress-esbuild-plugin. Also, how did you debug this plugin? I tried logging and throwing errors inside the setup function but I never saw any logs inside the terminal

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@@ -4,5 +4,5 @@ import { App } from './App'

it('renders hello world', () => {
mount(<App />)
cy.get('h1').contains('Hello World')
cy.get('h1').contains('Hello World').click()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this click()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. Without it, if we are displaying an overlay the tests will pass (even though they shouldn't). I can maybe throw a comment on there to make that more clear why I'm doing it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment added here: fd175c8 (#21599)

Copy link
Contributor

@JessicaSachs JessicaSachs May 25, 2022

Choose a reason for hiding this comment

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

.should('be.visible') btw is more "explicit" about what you're testing. Though .click()'s actionability checks are more aggressive (and will cover more failure cases)

@@ -296,12 +296,13 @@ Bluebird.config({
longStackTraces: true,
})

let cacheNodeModulesDir
Copy link
Contributor

Choose a reason for hiding this comment

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

Why were these changes needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. These were needed at one point to standardize output, but I refactored a few things and missed these. They are now removed:

fd175c8 (#21599)

cy.withCtx(async (ctx) => {
await ctx.actions.file.writeFileInProject(
`src/AppCompilationError.cy.jsx`,
`
Copy link
Contributor

Choose a reason for hiding this comment

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

Can use dedent here to indent the app code alongside the test without affecting the final file output if you like.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated to use dedent on the latest commit

name: 'esbuild-plugin',
setup (build) {
build.onEnd(function (result) {
// We don't want to completely fail the build here on errors so we treat the errors as warnings
Copy link
Contributor

Choose a reason for hiding this comment

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

Add link to #21599? I'd normally suggest linking the issue, but in this case it's in Jira and I prefer to link to github when possible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added here: fd175c8 (#21599)

@@ -93,42 +93,6 @@ export class CypressCTWebpackPlugin {
callback()
}

/*
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we removing the code to inform Cypress that there's a compilation error / success? It seems like this is an event we might want to react to in the UI in some way.

I'm thinking specifically of "compilation is done, rerun the spec" - right now we rely on webpack-dev-server's hot reload functionality, but I'd rather remove that and have Cypress do the hot reloading at some point.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See my comment below: #21599 (comment)

@@ -179,74 +178,6 @@ describe('#devServer', () => {
})
})

it('emits dev-server:compile:error event on error compilation', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

(just another mention of the above question - if we put back the dev-server:compile:error / dev-server:compile:success events, these tests would come back as well)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So there still is a dev-server:compile:success event. It's just in a different spot, but as I was thinking about this, I like having all of the compilation hooks in one place (they were definitely spread out and confusing before). With how everything works together we don't need the error events in vite or in webpack (however, that could change as this evolves in the future).

Unified the location of the compilation hooks here:

fd175c8 (#21599)

@@ -19,6 +19,9 @@ describe('makeWebpackConfig', () => {
output: {
publicPath: '/this-will-be-ignored',
},
devServer: {
overlay: true, // This will be ignored as well
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
overlay: true, // This will be ignored as well
overlay: true, // This will be overridden by makeWebpackConfig.ts

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated: fd175c8 (#21599)

@@ -4,5 +4,5 @@ import { App } from './App'

it('renders hello world', () => {
mount(<App />)
cy.get('h1').contains('Hello World')
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we clicking on hello world?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I want to ensure that the component is interactable (i.e. there's no overlay) I added a comment for this: fd175c8 (#21599)

Copy link
Member

@tgriesser tgriesser left a comment

Choose a reason for hiding this comment

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

Changes & rationale makes sense - good test coverage and it looks like the other review comments have been addressed, fine with me as long as tests look good 👍

export const run = (options: LaunchArgs, loadingPromise: Promise<void>) => {
// TODO: make sure if we need to run this in electron by default to match e2e behavior?
options.browser = options.browser || 'electron'
options.runAllSpecsInSameBrowserSession = true

require('../plugins/dev-server').emitter.on('dev-server:compile:error', (error: Error) => {
Copy link
Member

Choose a reason for hiding this comment

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

🔥 good riddance

Copy link
Contributor

Choose a reason for hiding this comment

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

god bless

@@ -17,4 +17,4 @@
import '@packages/frontend-shared/cypress/e2e/support/e2eSupport'

// Alternatively you can use CommonJS syntax:
// require('./commands')
require('./commands')
Copy link
Contributor

@JessicaSachs JessicaSachs May 25, 2022

Choose a reason for hiding this comment

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

I don't like mixing these. Why would you require instead of import? Not gonna block, but we should stick to one way of importing. require is nonstandard in the browser.

Copy link
Collaborator Author

@ryanthemanuel ryanthemanuel May 25, 2022

Choose a reason for hiding this comment

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

I can update this. That was my bad. I had just uncommented what was commented.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated here: dd566a0 (#21599)

Copy link
Contributor

@JessicaSachs JessicaSachs left a comment

Choose a reason for hiding this comment

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

Concerned about magicHtml usage. What's the deal with that?

publicPath: '/this-will-be-ignored',
},
devServer: {
magicHtml: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

This was added in Webpack 4.1 only. Will we break user config for Webpack 4? Is there a sys test for Webpack 4.0?

Copy link
Collaborator Author

@ryanthemanuel ryanthemanuel May 25, 2022

Choose a reason for hiding this comment

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

@JessicaSachs this is a unit test. I'm just verifying that user defined config will be kept (other than the ones we care about)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I saw that was just like "why this flag?". Cool.

export const run = (options: LaunchArgs, loadingPromise: Promise<void>) => {
// TODO: make sure if we need to run this in electron by default to match e2e behavior?
options.browser = options.browser || 'electron'
options.runAllSpecsInSameBrowserSession = true

require('../plugins/dev-server').emitter.on('dev-server:compile:error', (error: Error) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

god bless

@ryanthemanuel ryanthemanuel merged commit f2bce02 into develop May 25, 2022
@ryanthemanuel ryanthemanuel deleted the ryanm/fix/issue-with-compilation branch May 25, 2022 23:02
tgriesser added a commit that referenced this pull request May 27, 2022
…pack

* develop:
  fix: UNIFY-1408, warnings should be nested appropriately & clearable (#21630)
  chore: fix unit-tests-release job (#21652)
  chore(deps): update dependency eventsource to v2 [security] (#21639)
  fix: Add hover states for test titles in reporter (#21635)
  docs(CONTRIBUTING): Fix link to "good first issue" for newcomers (#21614)
  chore: compare `cy.screenshot` images in percy (#21598)
  fix: switching from ct to e2e (non-configured) does not go through setup (#21607)
  fix: issue with compilation failures in component testing (#21599)
  test: fix flaky launchpad test (#21637)
  docs: remove gitter link in contributing guide. (#21592)
  fix: order projects by most recently opened (#21589)
  fix: prevent crash on runs visit when offline (#21618)
  fix: pass family parameter to connect method (#21545)
  chore: clean up `debug` statements in preparation for 10.0 release, add `debug` docs (#21621)
  chore: add regression test for ts detection (#21578)
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.

5 participants