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: extends not working for some settings #4980

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

Conversation

manuth
Copy link

@manuth manuth commented Apr 24, 2023

Requirements

  • Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
  • All new code requires tests to ensure against regressions.

Description of the Change

As described in issue #4979, due to mocha first loading its default settings and after doing so processing the arguments using args, there are some settings which cannot be inherited by specifying an extends file:

Changes made in this PR processes configuration files using yargs right after they have been parsed. Thus, the order of events is now the following:

  • RC files are parsed
    • RC files are processed using yargs
  • package.json settings are loaded
  • Collected configs and argv get merged
  • mochas default values (from lib/mocharc.json) get applied

Alternate Designs

Configuration files could be processed right before mochas defaults get applied. However, the context of the file path would get lost thus causing relative extends paths to possibly fail.

Applying mochas default values could be removed from here:
https://github.com/mochajs/mocha/blob/37deed262d4bc0788d32c66636495d10038ad398/lib/cli
And instead be done somewhere around here (after yargs has been executed):

var args = mochaArgs || loadOptions(argv);

Why should this be in core?

Currently, the inheritance will not work for a number of settings while other settings do. This might cause confusion and unexpected results. Thus, I'd recommend to have this change in core.

Benefits

All settings will be able to be inherited while mochas defaults still get applied if necessary.

Possible Drawbacks

None that I have heard of.
If people already used extends for their own project, there is a chance that they relied on the inheritance of ui to not work, so there is a small possibility they will have to perform a one-time change to their config file.

Applicable issues

Or probably a minor as there is a small possibility people have to adjust their configuration if they used extends before

Co-authored-by: Pat Herlihy @mf-pherlihy

@manuth manuth changed the title Fix extends Fix Extends not Working for Some Settings Apr 24, 2023
@github-actions
Copy link
Contributor

This PR hasn't had any recent activity, and I'm labeling it stale. Remove the label or comment or this PR will be closed in 14 days. Thanks for contributing to Mocha!

@github-actions github-actions bot added the stale this has been inactive for a while... label Aug 25, 2023
@manuth
Copy link
Author

manuth commented Aug 25, 2023

Just pinging to have the stale label removed
I'd really love to see this implemented

@github-actions github-actions bot removed the stale this has been inactive for a while... label Aug 28, 2023
@JoshuaKGoldberg
Copy link
Member

Note: #4407 also touches this area. We should review them together in case one is a dup.

@JoshuaKGoldberg JoshuaKGoldberg added the semver-major implementation requires increase of "major" version number; "breaking changes" label Mar 1, 2024
Copy link
Member

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

Seems good and reasonable, nice! 🔥

Marking as requesting changes just so we can chat about the two possible implementations a bit.

test/integration/options.spec.js Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

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

[Praise] As with #4407's tests, these are nice! I like that this also has an added second one for both --config and file coverage.


config = yargs(undefined, path.dirname(filepath))
.parserConfiguration(require('./options').YARGS_PARSER_CONFIG)
.config(config);
Copy link
Member

Choose a reason for hiding this comment

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

Noting https://github.com/mochajs/mocha/pull/4407/files#r1509449877 here: would be nice to have discussion on which API option to use. I'm leaning towards this one, but want to hear if there are advantages to applyExtends I missed.

Copy link
Member

Choose a reason for hiding this comment

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

Oh darn I wasn't very clear on this. I wanted to ask you @manuth as well as @mochajs/maintenance-crew, does anybody have opinions on using this API vs. yargs/helpers -> applyExtends? I'm in favor as-is, but since two PRs tried two different approaches I think I'd want to see if anybody prefers the other approach.

Copy link
Author

Choose a reason for hiding this comment

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

I'm not entirely sure anymore why I decided to use this function instead.
I remember that when using a different approach, some options were overridden by default.

I will read through my commit messages during the upcoming weekend. I really hope I can reproduce my thoughts this way.

Copy link
Member

Choose a reason for hiding this comment

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

👋 just checking in @manuth, anything I can help with?

Copy link
Author

Choose a reason for hiding this comment

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

Closing this convo as I've addressed this in my latest comment:
#4980 (comment)

Sorry for letting you wait for so long.

test/integration/options.spec.js Show resolved Hide resolved
@JoshuaKGoldberg JoshuaKGoldberg added the status: waiting for author waiting on response from OP - more information needed label Mar 1, 2024
@JoshuaKGoldberg
Copy link
Member

Marking as semver-major because some projects might accidentally be relying on the current, arguably broken behavior.

@JoshuaKGoldberg JoshuaKGoldberg changed the title Fix Extends not Working for Some Settings fix: extends not working for some settings Mar 4, 2024
@JoshuaKGoldberg JoshuaKGoldberg added status: needs review a maintainer should (re-)review this pull request and removed status: waiting for author waiting on response from OP - more information needed labels Aug 6, 2024
@JoshuaKGoldberg JoshuaKGoldberg dismissed their stale review August 6, 2024 15:16

Conversations resolved.

@JoshuaKGoldberg JoshuaKGoldberg added the status: waiting for author waiting on response from OP - more information needed label Oct 8, 2024
king-2929

This comment was marked as spam.

king-2929

This comment was marked as spam.

@JoshuaKGoldberg
Copy link
Member

👋 just checking in @manuth, anything I can help with?

@manuth
Copy link
Author

manuth commented Jan 3, 2025

Alright, so I made a little digging.
Of course, I might be wrong with my conclusions, so I'm open to feedback.

As described in issue #4979, the underlying issue that causes Mocha to ignore certain settings from extends-files is, that Mocha first applies its defaults to the provided configuration and, only after that, processes the config using yargs. Let's call this behaviour "Late Yargs Processing", which is explained in detail in it's own section.

In order to fix this, yargs must be run early or more precisely:
yargs must run before Mocha's global defaults are applied.

My solution was to run yargs in the function used by Mocha to load config files:

mocha/lib/cli/config.js

Lines 81 to 83 in f131e9a

config = yargs(undefined, path.dirname(filepath))
.parserConfiguration(require('./options').YARGS_PARSER_CONFIG)
.config(config);

The solution proposed by @mf-pherlihy is to process the config using yargs not while loading the configuration but rather after loading the configuration, in the parse function, which is still before Mocha applies its global defaults:

mocha/lib/cli/options.js

Lines 130 to 142 in f07d427

configObjects: configObjects.map(configObject => {
// '_configPath' gets set by config.loadConfig()
const config = configObject || {};
const configPath =
typeof config._configPath === 'string'
? path.dirname(config._configPath)
: cwd();
// Remove the internal property
delete config._configPath;
return applyExtends(config, configPath, true);
}),

Conclusion

Of course, I might be biased as former solution is written by me while latter isn't.
I consider my solution more clean and future-proof. Especially considering that loadRc is an exported function and using it might re-introduce the issue if my solution weren't implemented.

Furthermore, it uses yarg's yargs-function which seems like "more public" API to me than the yargs/helpers=> applyExtends function (I guess?).

However, there are more...

Things to Consider

I have just noticed that RC config files aren't the only place where the extends option reasonably might occur. One more spot is the package.json file.

I'd recommend adding a function (like processConfig(config, filePath) - recommendations welcome, though) to lib/cli/options.js which processes expands the extends option using yargs that we can use for both RC config files (in the loadRc function) and the package.json file (in the loadPkgRc function).
For this to happen, slight changes need to be made to this PR.

One more thing is that currently, because yargs has no knowledge of the original location of configuration files, the extends-file path is relative to the working directory. After implementing either of the solutions, the extends-file will be relative to the corresponding configuration file. This should be mentioned somewhere in the changelog, I guess.

Late Yargs Processing

Mocha processing the configuration using yargs at a late stage causes certain settings from extends-files to be ignored.
I will describe a case in some greater detail here.

Let's imagine a config file:
.mocharc.json:

{
  "extends": "./base.json",
  "timeout": 1000
}

And base config:
base.json:

{ "ui": "tdd" }

First, at this line, Mocha will apply the global defaults to the config:

const opts = loadOptions(process.argv.slice(2));

or, when called through _mocha:
var args = mochaArgs || loadOptions(argv);

Making the runtime-configuration at this point look like this:

Runtime-Config After loadOptions:

{
  "_": [],
  "config": false,
  "package": false,
  "extends": "./base.json",
  "timeout": 1000,
  "diff": true,
  "extension": [
    "js",
    "cjs",
    "mjs"
  ],
  "reporter": "spec",
  "slow": 75,
  "ui": "bdd",
  "watch-ignore": [
    "node_modules",
    ".git"
  ]
}

Note:
Take especial note that the ui setting now is already set to Mocha's global default bdd loaded from the mocharc variable here:

mocha/lib/cli/options.js

Lines 315 to 322 in 75dcf8c

args = parse(
args._,
mocharc,
args,
envConfig,
rcConfig || {},
pkgConfig || {}
);

After that, yargs is executed on the config here:

.config(args)

You will notice, that the configuration ui option remains unchanged. That's, ofc, as you might remember from the previous Runtime-Config dump, because of the fact that a few settings, including ui, are now set in the config object, which override the ui set in the extends-file. Thus, the ui option and all further global defaults set in the mocharc variable cannot be set using extends.

At time of writing, the mocharc variable is loaded from this file:
https://github.com/mochajs/mocha/blob/75dcf8c6c40ed1ce134ae5e174b6f4c4ca4d8c42/lib/mocharc.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-major implementation requires increase of "major" version number; "breaking changes" status: needs review a maintainer should (re-)review this pull request status: waiting for author waiting on response from OP - more information needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants