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

feat(core): use user configured npm registry #4937

Merged
merged 8 commits into from
Aug 22, 2024

Conversation

Tamir-M
Copy link
Contributor

@Tamir-M Tamir-M commented Aug 6, 2024

Copy link
Member

@nicojs nicojs left a comment

Choose a reason for hiding this comment

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

Thanks for the PR. I have some remarks.

packages/core/src/initializer/index.ts Show resolved Hide resolved
@@ -65,7 +65,7 @@ export class NpmClient {
const response = await this.innerNpmClient.get<NpmSearchResult>(path);
return handleResult(path)(response);
} catch (err) {
this.log.error(`Unable to reach 'https://registry.npmjs.com' (for query ${path}). Please check your internet connection.`, errorToString(err));
this.log.error(`Unable to reach '${getRegistry()}' (for query ${path}). Please check your internet connection.`, errorToString(err));
Copy link
Member

Choose a reason for hiding this comment

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

Instead of using getRegistry here, you can simply let the npm registry location be injected, see previous comment about dependency injection

const NPM_REGISTRY = 'https://registry.npmjs.com';
let currentRegistry: string | undefined;

function getRegistry(): string {
Copy link
Member

Choose a reason for hiding this comment

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

Can you add unit tests for this function? Also, move it to a separate file.

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 am having some issues with the last case where I would need to use the execaSync, I have a few ways I can test this:

Mocking:
Would result in not actually testing the functionality of it, wouldn't do anything.

Editing the npm config:
This may cause a problem if I do beforeEach and afterEach to edit the npm config there are multiple things that could happen:

  • If the command fails it can ruin the person's npm configuration.
  • If the person aborts mid test it could ruin the person's npm configuration.

Seems like too be too many points of failure.
I have no idea how to test this or if I even should, as I gave a default value if it fails and warned them.
I would wait for your input.

Copy link
Member

@nicojs nicojs Aug 11, 2024

Choose a reason for hiding this comment

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

Ah yes, great question. Please add 2 more unit tests, 1 for the happy flow and one for the alternate flow using mocking of execaSync. You are right that we won't test the actual command npm config get registry, but I would expect that to work as documented. However, if you want to add a test for that, you are welcome to add an integration test (see test/integration).

To mock out execSync, we can't simply use sinon.stub(execa, 'execSync'), since it isn't a method that's being called, but rather a function that is directly exported. To mock it away, we can use the same approach as we did for execaCommand, see the coreTokens.execa for an example. So you can add a coreTokens.execaSync token.

currentRegistry = 'https://registry.npmjs.com';
} else {
// Using global as when trying to get the registry inside npm workspace it would fail
const registry = execaSync('npm', ['config', 'get', '--global', 'registry'], {
Copy link
Member

Choose a reason for hiding this comment

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

Please also add a try ... catch here, because a lot of stuff can go wrong here. If an error occurs we should log a warning (using the logger that you can inject) and use the default value,

timeout: 20000,
});

currentRegistry = registry.stdout;
Copy link
Member

Choose a reason for hiding this comment

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

Should the result be trimmed here?

Suggested change
currentRegistry = registry.stdout;
currentRegistry = registry.stdout.trim();

move getRegistry to a different file, wrap `execaSync` in try-catch, and use dependency injection, and changed tests to run
@Tamir-M
Copy link
Contributor Author

Tamir-M commented Aug 11, 2024

@nicojs I've applied the changes.

Copy link
Member

@nicojs nicojs left a comment

Choose a reason for hiding this comment

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

Thanks for fixing my review comments. I have some final remarks regarding the tests.

Note: if you need help to create a mock for execSync, feel free to ask, I would be happy to help out.


process.env.npm_command = 'value';

const registry = getRegistry(log4js.getLogger());
Copy link
Member

Choose a reason for hiding this comment

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

Please use testInjector.logger. It contains a logger mock that is ready to be used. You can verify log messages on it using sinon.asserts.calledOnceWithExactly(testInjector.logger.warn, '...');


process.env.npm_command = 'value';

const registry = getRegistry(log4js.getLogger());
Copy link
Member

Choose a reason for hiding this comment

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

Same here

@@ -55,7 +56,8 @@ describe(StrykerInitializer.name, () => {
syncBuiltinESMExports();
sut = testInjector.injector
.provideValue(initializerTokens.out, out as unknown as typeof console.log)
.provideValue(initializerTokens.restClientNpm, npmRestClient)
.provideFactory(initializerTokens.npmRegistry, getRegistry)
.provideFactory(initializerTokens.restClientNpm, createNpmRegistryClient)
Copy link
Member

Choose a reason for hiding this comment

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

Since this is a unit test for the StrykerInitializer, I wouldn't expect the "real" getRegistry to be used here. Instead, you can keep using provideValue here for the npmRestClient sinon mock here.

Indeed, the tests are failing, see https://github.com/stryker-mutator/stryker-js/actions/runs/10341544430/job/28626286827?pr=4937

@Tamir-M
Copy link
Contributor Author

Tamir-M commented Aug 21, 2024

@nicojs I've applied the changes you've asked for, would love to get them reviewed.

Copy link
Member

@nicojs nicojs left a comment

Choose a reason for hiding this comment

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

Thanks a lot for implementing the requested changes! I've got small remarks about the use of test hooks and assertions. Other than that this looks good.

let oldNpmConfigRegistry: string | undefined;
let oldNpmCommand: string | undefined;

before(() => {
Copy link
Member

Choose a reason for hiding this comment

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

This should be beforeEach instead of before (or change afterEach to be after)

Comment on lines 55 to 59
sinon.assert.callCount(execaCommandSyncMock, 1);
sinon.assert.calledWith(execaCommandSyncMock, 'npm config get --global registry', {
stdout: 'pipe',
timeout: 20000,
});
Copy link
Member

Choose a reason for hiding this comment

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

Can be simplified to calledOnceWithExactly

Comment on lines 74 to 78
sinon.assert.callCount(execaCommandSyncMock, 1);
sinon.assert.calledWith(execaCommandSyncMock, 'npm config get --global registry', {
stdout: 'pipe',
timeout: 20000,
});
Copy link
Member

Choose a reason for hiding this comment

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

Same here

@Tamir-M
Copy link
Contributor Author

Tamir-M commented Aug 22, 2024

Thank you for the remarks, I've applied them.

Copy link
Member

@nicojs nicojs left a comment

Choose a reason for hiding this comment

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

LGTM

@nicojs nicojs enabled auto-merge (squash) August 22, 2024 11:23
@nicojs nicojs merged commit 33e348e into stryker-mutator:master Aug 22, 2024
7 checks passed
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.

2 participants