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

formatters: include html-formatter as a built-in option #1432

Merged
merged 19 commits into from
Oct 2, 2020

Conversation

davidjgoss
Copy link
Contributor

FIxes #1425

@davidjgoss
Copy link
Contributor Author

davidjgoss commented Sep 11, 2020

I have an issue with this where the output file will end just after the script tags that sets CUCUMBER_MESSAGES. From a bit of debugging it seems the cleanup() that closes the write stream is done before our CucumberHtmlStream has finished working. Confirmed by putting an artificial wait before cleanup() where I can then get the full output correctly.

I think we need a way for formatters to indicate they are doing some asynchronous work, so we can let them finish before cleaning up. I'll have a go at doing that in a lightweight way now. In the meantime let me know if I'm missing something (I am pretty new to streams in Node so may well be).

@davidjgoss davidjgoss marked this pull request as ready for review September 11, 2020 20:03
return async function () {
await bluebird.each(formatters, async (formatter) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Almost all of the rest of this file is just indentation changes - this is the addition, where we wait for each formatter to be finished.

Copy link
Member

@charlierudolph charlierudolph Sep 13, 2020

Choose a reason for hiding this comment

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

Thoughts on making the default formatter finished function end the stream?
Then for the html formatter, it waits for the cucumber html stream to finish and then also awaits on super? Think that simplifies this a little bit.

Copy link
Contributor Author

@davidjgoss davidjgoss Sep 13, 2020

Choose a reason for hiding this comment

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

That does seem like a good balance.

In cases where the formatter has asked to write to stdout, we can't just end the stream when the formatter is done writing, because the process still needs stdout. The current code accounts for this by not adding it to the list of streams to end.

Copy link
Contributor

Choose a reason for hiding this comment

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

If a formatter's writable stream is written to by piping another readable stream into it, then we just have to wait until the pipe is finished. We cannot prematurely close it.

This is what's happening in this case. The CucumberHtmlStream is piped to the formatter's stream. We have no control over when it's done.

Copy link
Contributor Author

@davidjgoss davidjgoss Sep 13, 2020

Choose a reason for hiding this comment

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

Okay I have pushed something which I believe accounts for all of this whilst keeping a straightforward API for formatter authors - though not sure it really comes out any simpler. Let me know what you think. Also clarified my comment above.

Copy link
Contributor

Choose a reason for hiding this comment

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

That does seem like a good balance.

In cases where the formatter has asked to write to stdout, we can't just end the stream when the formatter is done writing, because the process still needs stdout. The current code accounts for this by not adding it to the list of streams to end.

I think it would be best to wait for it to have written everything. The correct way to keep stdout open is to stream.pipe(process.stdout, {end: false})

@aslakhellesoy
Copy link
Contributor

The question is - who's responsible for closing a formatter stream? Is it the formatter itself, or is it the runner?

In Cucumber-JVM it's each formatter's responsibility to close the stream, which is passed to it via its constructor. They all do this when they receive a TestRunFinished message. Here is an example.

In Cucumber-Ruby it's different. Streams are closed by the runtime before the interpreter exits. This happens in an at_exit hook.

Cucumber.js currently uses the same approach as Cucumber-Ruby. I think this is wrong. I don't think we can use process.on('exit') - I don't think it will fire until all streams are closed. Besides it won't work in a browser.

Adding a timeout is not a good solution either, as it slows down execution.

I think we should adopt the Cucumber-JVM model where formatters close streams themselves. This hasn't been a problem before, because all our formatters are synchronous. The HTML formatter is not, which is why this problem has surfaced now.

I'm not sure how common 3rd party formatters are on cucumber.js. My proposed change would be backwards incompatible. Existing formatters that don't close their own stream would cause Cucumber to hang. I think we should try to make this change before we cut 7.x.

Thoughts @davidjgoss @charlierudolph @vincent-psarga @mpkorstanje?

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Sep 11, 2020

I think we should adopt the Cucumber-JVM model where formatters close streams themselves.

I wouldn't copy the Cucumber JVM model. Rather I'd make the plugins implement a Closable interface which delegates to the Outpustream. Then the plugins can be treated as resources and closed at the end of the test execution. Currently this is not possible in Cucumber JVM because it lacks a complete life cycle.

@davidjgoss
Copy link
Contributor Author

davidjgoss commented Sep 11, 2020

@aslakhellesoy

FWIW I changed the approach a bit here and it now works correctly. It's not that dissimilar from what you're saying in that formatters now have to declare when they are finished (rather than close the output stream themselves), but by extending the built-in Formatter you inherit the default which is "immediately".

I'm not sure how common 3rd party formatters are on cucumber.js.

Not sure - there are a couple of popular HTML ones out there I think - at any rate 7.0.0 is already a breaking change for formatters.

CHANGELOG.md Outdated Show resolved Hide resolved
@davidjgoss
Copy link
Contributor Author

@charlierudolph @aslakhellesoy looping back to this - I know we went back and forth a bit on streams, but I'm not really sure how to improve meaningfully on what's here. It does work correctly, doesn't end streams prematurely etc, and we have got the interface for formatters to finish asynchronously in a non-breaking way. Is this okay to go in?

@davidjgoss davidjgoss merged commit bfb66fa into master Oct 2, 2020
@davidjgoss davidjgoss deleted the include-html-formatter branch October 2, 2020 08:17
@raszi
Copy link

raszi commented Oct 2, 2020

Thank you for this work! When are you planning to release this, I just wanted to use this and I realized that it has been just merged. :)

@davidjgoss
Copy link
Contributor Author

@raszi this should be in 7.0.0 in the next week or so

Adam-ARK pushed a commit to Adam-ARK/cucumber-js that referenced this pull request Oct 21, 2020
* add html formatter as dependency

* update run-script to use local install

* add doc

* add as first party formatter in switch

* create our new formatter

* use in formatters test

* changelog, improve doc a bit

* add pre script to make sure we're built

* add concept of an async `finished` method on formatters

* rework so it works

* test html formatter roughly via formatters feature test

* dont need this on the test path now

* whoops missed one

* what even is a computer

* end stream from within formatter finished method except if stdout

* update changelog again

* fix botched merge
@nickgrealy
Copy link

@raszi this should be in 7.0.0 in the next week or so

@davidjgoss - looking forward to this - when's the next release candidate?

@davidjgoss
Copy link
Contributor Author

@nickgrealy sorry for delay, 7.0.0 was released today

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.

HTML Formatter
6 participants