react-native/scripts/releases-ci/__tests__/publish-updated-packages-test.js
Nicola Corti cb6ea49123 Fix warning on scripts/releases-ci/__tests__/publish-updated-packages-test.js (#45643)
Summary:
This just fixes a warning in scripts/releases-ci/__tests__/publish-updated-packages-test.js that the CI is firing on every PR

## Changelog:

[INTERNAL] - Fix warning on scripts/releases-ci/__tests__/publish-updated-packages-test.js

Pull Request resolved: https://github.com/facebook/react-native/pull/45643

Test Plan: CI

Reviewed By: blakef

Differential Revision: D60170227

Pulled By: cortinico

fbshipit-source-id: 5889f7dd530cc00651d683001e1f2624bd79c27e
2024-07-24 12:41:00 -07:00

280 lines
7.5 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
const {
getTagsFromCommitMessage,
publishUpdatedPackages,
} = require('../publish-updated-packages');
const getPackagesMock = jest.fn();
const execSync = jest.fn();
const execMock = jest.fn();
const fetchMock = jest.fn();
jest.mock('child_process', () => ({execSync}));
jest.mock('shelljs', () => ({exec: execMock}));
jest.mock('../../utils/monorepo', () => ({
getPackages: getPackagesMock,
}));
// $FlowIgnore[cannot-write]
global.fetch = fetchMock;
const BUMP_COMMIT_MESSAGE =
'bumped packages versions\n\n#publish-packages-to-npm';
describe('publishUpdatedPackages', () => {
beforeEach(() => {
jest.spyOn(console, 'log').mockImplementation(() => {});
jest.resetAllMocks();
});
test('should exit with error if not in a Git repo', async () => {
execSync.mockImplementation((command: string) => {
switch (command) {
case 'git log -1 --pretty=%B':
throw new Error();
}
});
jest.spyOn(console, 'error').mockImplementation(() => {});
let message = '';
try {
await publishUpdatedPackages();
} catch (e) {
message = e.message;
}
expect(message).toEqual('Failed to read Git commit message, exiting.');
});
test("should exit when commit message does not include '#publish-packages-to-npm'", async () => {
execSync.mockImplementation((command: string) => {
switch (command) {
case 'git log -1 --pretty=%B':
return 'A non-bumping commit';
}
});
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
await publishUpdatedPackages();
expect(consoleLog.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"Current commit does not include #publish-packages-to-npm keyword, skipping.",
],
]
`);
});
test('should throw an error if updated version is not 0.x.x', async () => {
execSync.mockImplementation((command: string) => {
switch (command) {
case 'git log -1 --pretty=%B':
return BUMP_COMMIT_MESSAGE;
}
});
const mockedPackageNewVersion = '1.0.0';
getPackagesMock.mockResolvedValue({
'@react-native/package-a': {
path: 'absolute/path/to/package-a',
packageJson: {
version: mockedPackageNewVersion,
},
},
});
fetchMock.mockResolvedValueOnce({
json: () => Promise.resolve({versions: {}}),
});
await expect(publishUpdatedPackages()).rejects.toThrow(
`Package version expected to be 0.x.x, but received ${mockedPackageNewVersion}`,
);
});
test('should publish all updated packages', async () => {
execSync.mockImplementation((command: string) => {
switch (command) {
case 'git log -1 --pretty=%B':
return BUMP_COMMIT_MESSAGE;
}
});
getPackagesMock.mockResolvedValue({
'@react-native/package-a': {
name: '@react-native/package-a',
path: 'absolute/path/to/package-a',
packageJson: {
version: '0.72.1',
},
},
'@react-native/package-b': {
name: '@react-native/package-b',
path: 'absolute/path/to/package-b',
packageJson: {
version: '0.72.1',
},
},
'@react-native/package-c': {
name: '@react-native/package-c',
path: 'absolute/path/to/package-c',
packageJson: {
version: '0.72.0',
},
},
});
fetchMock.mockResolvedValue({
json: () =>
Promise.resolve({
versions: {'0.72.0': {}},
}),
});
execMock.mockImplementation(() => ({code: 0}));
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
await publishUpdatedPackages();
expect(consoleLog.mock.calls.flat().join('\n')).toMatchInlineSnapshot(`
"Discovering updated packages
- Skipping @react-native/package-c (0.72.0 already present on npm)
Done ✅
Publishing updated packages to npm
- Publishing @react-native/package-a (0.72.1)
- Publishing @react-native/package-b (0.72.1)
Done ✅"
`);
expect(execMock.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-a",
},
],
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-b",
},
],
]
`);
});
describe('retry behaviour', () => {
beforeEach(() => {
execSync.mockImplementation((command: string) => {
switch (command) {
case 'git log -1 --pretty=%B':
return BUMP_COMMIT_MESSAGE;
}
});
getPackagesMock.mockResolvedValue({
'@react-native/package-a': {
name: '@react-native/package-a',
path: 'absolute/path/to/package-a',
packageJson: {
version: '0.72.1',
},
},
'@react-native/package-b': {
name: '@react-native/package-b',
path: 'absolute/path/to/package-b',
packageJson: {
version: '0.72.1',
},
},
});
fetchMock.mockResolvedValue({
json: () =>
Promise.resolve({
versions: {'0.72.0': {}},
}),
});
});
test('should retry once if `npm publish` fails', async () => {
execMock.mockImplementationOnce(() => ({code: 0}));
execMock.mockImplementationOnce(() => ({
code: 1,
stderr: '503 Service Unavailable',
}));
execMock.mockImplementationOnce(() => ({code: 0}));
const consoleError = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
await publishUpdatedPackages();
expect(consoleError.mock.calls.flat().join('\n')).toMatchInlineSnapshot(`
"Failed to publish @react-native/package-b. npm publish exited with code 1:
503 Service Unavailable"
`);
expect(execMock.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-a",
},
],
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-b",
},
],
Array [
"npm publish",
Object {
"cwd": "absolute/path/to/package-b",
},
],
]
`);
});
test('should exit with error if one or more packages fail after retry', async () => {
execMock.mockImplementationOnce(() => ({code: 0}));
execMock.mockImplementation(() => ({
code: 1,
stderr: '503 Service Unavailable',
}));
const consoleLog = jest
.spyOn(console, 'log')
.mockImplementation(() => {});
let message = '';
try {
await publishUpdatedPackages();
} catch (e) {
message = e.message;
}
expect(consoleLog).toHaveBeenLastCalledWith('--- Retrying once! ---');
expect(message).toEqual('Failed packages count = 1');
});
});
});
describe('getTagsFromCommitMessage', () => {
test('should parse tags', () => {
const commitMsg = `${BUMP_COMMIT_MESSAGE}&tagA&tagB&tagA\n`;
expect(getTagsFromCommitMessage(commitMsg)).toEqual([
'tagA',
'tagB',
'tagA',
]);
});
});