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 Dredd.js, improve integration tests coverage, drop Node 6 support #1317

Merged
merged 8 commits into from May 2, 2019

Conversation

honzajavorek
Copy link
Contributor

@honzajavorek honzajavorek commented Apr 4, 2019

πŸš€ Why this change?

I didn't like most of the Dredd.js file. This should streamline the pipeline from API description locations to parse results and transactions. The refactoring prepares ground for #1191. With #1275 it could be further refactored and streamlined.

I still feel like I did this, but I hope it is still improvement in gradually isolating stuff.

πŸ“ Related issues and Pull Requests

βœ… What didn't I forget?

  • To write docs
  • To write tests
  • To put Conventional Changelog prefixes in front of all my commits and run npm run lint

@honzajavorek honzajavorek force-pushed the honzajavorek/refactor-dredd-js branch 3 times, most recently from eba7565 to b67c6b5 Compare April 9, 2019 13:19
@@ -1,21 +1,89 @@
const async = require('async');
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 code of this file still seems ugly to me at many places and I blame mainly the asynchronous parts. I hope with async/await/promises it could get even more readable and unit-testable in the future.

const resolveModule = require('./resolveModule');
const logger = require('./logger');
const TransactionRunner = require('./TransactionRunner');
const { applyConfiguration } = require('./configuration');


const FILE_DOWNLOAD_TIMEOUT = 5000;
function prefixErrors(decoratedCallback, prefix) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't come up with a nicer way how to prefix errors with context than decorating the callback like this. I might be just missing a good idea or a best practise. But it's gonna disappear with async/await/promises anyway.

}


function readLocations(locations, options, callback) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I feel like readLocations() and parseContent() might get a lot slimmer or even redundant with Promise.all() or Promise.map(), but I decided to stay with callbacks until Dredd drops Node 6 support.

}

this.logger.debug('Resolving API descriptions locations');
prepareAPIdescriptions(callback) {
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 prepareAPIdescriptions() method isn't a real method of a real object as the Dredd class doesn't need to be a class in the first place. I created it just to make run() shorter. It roughly contains the pipeline turning API description locations into API descriptions, then parsing them, and then compiling them into transactions. Once we have async/await/promises and the code is less tied with 'this.configuration', it might make sense to refactor this further.

Is the provided path correct?
`);
return callback(err);
run(callback) {
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 Dredd class represents an object with just a single (asynchronous...) method, run(). That's an antipattern and a clear indication it doesn't need to be a class at all. It is interconnected by references with reporters though and it's Dredd's public JavaScript API, so I'm leaving it as a class for now. Also for now ignoring the fact that it calls the callback with both error and the stats (fixing it would be a breaking change). In the future I can imagine even something like const stats = await dredd(config);

.map(transaction => (Object.assign({ apiDescriptionMediaType: compileResult.mediaType }, transaction)));
next();
this.logger.debug('Configuring reporters');
configureReporters(this.configuration, this.stats, this.transactionRunner);
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 configureReporters() is a rabbit hole of side effects. Leaving it as it is for now.

this.configuration.apiDescriptions = apiDescriptions;

// TODO https://github.com/apiaryio/dredd/issues/1191
const annotationsError = handleRuntimeProblems(apiDescriptions, this.logger);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want to get rid of handleRuntimeProblems() as the next step after this PR, finally unblocking upgrading Dredd Transactions.

@honzajavorek honzajavorek marked this pull request as ready for review April 9, 2019 13:29
@honzajavorek honzajavorek requested review from kylef and artem-zakharchenko and removed request for kylef April 9, 2019 13:29
@honzajavorek honzajavorek added this to In progress in SJS Apr 11, 2019
lib/Dredd.js Show resolved Hide resolved
lib/Dredd.js Outdated
try {
return compile(mediaType, apiElements, location);
} catch (error) {
error.message = (
Copy link
Contributor

Choose a reason for hiding this comment

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

If you separate the decoration logic from the prefixError so it doesn't include a callback dispatch, you can reuse it here.

const decorateError = (error, prefix) => {
  error.message = `${prefix}: ${error.message}`
  return error
}

const prefixError = (...) => {
  // ...
  decodateError(...)
  // handle callbacks and stuff
}

// compileTransactions
// ...
} catch (error) {
  decorateError(error, 'Unable to compile ...')
}

lib/Dredd.js Outdated
this.files = resolveLocations(this.configuration.custom.cwd, this.configuration.options.path);
} catch (err) {
callback(err, this.stats);
locations = resolveLocations(this.configuration.custom.cwd, this.configuration.options.path);
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to time the merges of this and configuration pull request. I vote for merging configuration updates first, since they didn't touch any actual logic in Dredd, or other files, but simply removed the .options. nesting from internal usage. It would be much more simple to remove options nesting than ensure the logic introduced by your pull request is not lost.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree, let's merge yours first. Also, your PR is semantically unreleasable, but this is a breaking change, so if yours goes first, my will release both.

lib/TransactionRunner.js Show resolved Hide resolved
const status = parseInt(response.status, 10);
if ((status < 200) || (status >= 300)) {
skip = true;
}
}
delete transaction.apiDescriptionMediaType;
delete transaction.apiDescription;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is deleting the whole description intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. It is currently passed along only for the purpose of checking the media type above. I have future plans with it, so I keep it as an object, but currently it is not further used anywhere else, so I'm removing it immediately after it's used, to prevent it to leak into hooks etc.

lib/isURL.js Show resolved Hide resolved
// flattens the array of arrays
.reduce((flatArray, array) => flatArray.concat(array), [])
// removes duplicates
.filter((location, index, array) => !array.slice(0, index).includes(location));
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 use new Set() to achieve the same output?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure πŸ€¦β€β™‚οΈ That's even how resolvePaths() does it...

test/integration/js-interface-test.js Show resolved Hide resolved
assert.instanceOf(dreddRuntimeInfo.err, Error);
});
it('passes expected stats to the callback', () => {
assert.hasAllKeys(dreddRuntimeInfo.stats, [
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 separate the list of Dredd's stats keys into a enum?

test/unit/isURL-test.js Show resolved Hide resolved
@honzajavorek
Copy link
Contributor Author

@artem-zakharchenko Thanks for the review! πŸ™ I'll add a few commits to address your comments and then, if you approve, let's block this PR until yours gets merged.

@honzajavorek honzajavorek force-pushed the honzajavorek/refactor-dredd-js branch from 0ac9b7c to d3d77c3 Compare April 30, 2019 16:22
@honzajavorek honzajavorek changed the title Refactor Dredd.js, improve integration tests coverage Refactor Dredd.js, improve integration tests coverage, drop Node 6 support Apr 30, 2019
@honzajavorek
Copy link
Contributor Author

I rebased this against master. As this is going to be a breaking change again because of 59702d4, I'll add a commit dropping Node 6 support, to lower the frequency of major Dredd releases per day πŸ“ˆ

Allowing for #1275

BREAKING CHANGE: Dredd does not support Node 6 anymore. Node 6 has a scheduled maintenance end on April 2019.
Copy link
Contributor

@artem-zakharchenko artem-zakharchenko left a comment

Choose a reason for hiding this comment

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

Looks good to me. Thank you for the changes.

@honzajavorek honzajavorek merged commit 429e709 into master May 2, 2019
SJS automation moved this from In progress to Done May 2, 2019
@honzajavorek honzajavorek deleted the honzajavorek/refactor-dredd-js branch May 2, 2019 13:47
@ApiaryBot
Copy link
Collaborator

πŸŽ‰ This PR is included in version 11.0.0 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
SJS
  
Done
Development

Successfully merging this pull request may close these issues.

Reorganization and cleanup of Dredd.js Integration Tests
3 participants