/** * 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. * * @format */ const { publishTemplate, verifyPublishedTemplate, } = require('../publishTemplate'); const mockRun = jest.fn(); const mockSleep = jest.fn(); const mockGetNpmPackageInfo = jest.fn(); const silence = () => {}; jest.mock('../utils.js', () => ({ log: silence, run: mockRun, sleep: mockSleep, getNpmPackageInfo: mockGetNpmPackageInfo, })); const getMockGithub = () => ({ rest: { actions: { createWorkflowDispatch: jest.fn(), }, }, }); describe('#publishTemplate', () => { beforeEach(jest.clearAllMocks); it('checks commits for magic #publish-package-to-npm&latest string and sets latest', async () => { mockRun.mockReturnValueOnce(` The commit message #publish-packages-to-npm&latest`); const github = getMockGithub(); await publishTemplate(github, '0.76.0', true); expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({ owner: 'react-native-community', repo: 'template', workflow_id: 'release.yaml', ref: '0.76-stable', inputs: { dry_run: true, is_latest_on_npm: true, version: '0.76.0', }, }); }); it('pubished as is_latest_on_npm = false if missing magic string', async () => { mockRun.mockReturnValueOnce(` The commit message without magic `); const github = getMockGithub(); await publishTemplate(github, '0.76.0', false); expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledWith({ owner: 'react-native-community', repo: 'template', workflow_id: 'release.yaml', ref: '0.76-stable', inputs: { dry_run: false, is_latest_on_npm: false, version: '0.76.0', }, }); }); }); describe('#verifyPublishedTemplate', () => { beforeEach(jest.clearAllMocks); it("waits on npm updating for version and not 'latest'", async () => { const NOT_LATEST = false; mockGetNpmPackageInfo // template@ .mockReturnValueOnce(Promise.reject('mock http/404')) .mockReturnValueOnce(Promise.resolve()); mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => { throw new Error('Should not be called again!'); }); const version = '0.77.0'; await verifyPublishedTemplate(version, NOT_LATEST); expect(mockGetNpmPackageInfo).toHaveBeenLastCalledWith( '@react-native-community/template', version, ); }); it('waits on npm updating version and latest tag', async () => { const IS_LATEST = true; const version = '0.77.0'; mockGetNpmPackageInfo // template@latest → unknown tag .mockReturnValueOnce(Promise.reject('mock http/404')) // template@latest != version → old tag .mockReturnValueOnce(Promise.resolve({version: '0.76.5'})) // template@latest == version → correct tag .mockReturnValueOnce(Promise.resolve({version})); mockSleep .mockReturnValueOnce(Promise.resolve()) .mockReturnValueOnce(Promise.resolve()) .mockImplementation(() => { throw new Error('Should not be called again!'); }); await verifyPublishedTemplate(version, IS_LATEST); expect(mockGetNpmPackageInfo).toHaveBeenCalledWith( '@react-native-community/template', 'latest', ); }); describe('timeouts', () => { let mockProcess; beforeEach(() => { mockProcess = jest.spyOn(process, 'exit').mockImplementation(code => { throw new Error(`process.exit(${code}) called!`); }); }); afterEach(() => mockProcess.mockRestore()); it('will timeout if npm does not update package version after a set number of retries', async () => { const RETRIES = 2; mockGetNpmPackageInfo.mockReturnValue(Promise.reject('mock http/404')); mockSleep.mockReturnValue(Promise.resolve()); await expect(() => verifyPublishedTemplate('0.77.0', true, RETRIES), ).rejects.toThrowError('process.exit(1) called!'); expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES); }); it('will timeout if npm does not update latest tag after a set number of retries', async () => { const RETRIES = 7; const IS_LATEST = true; mockGetNpmPackageInfo.mockReturnValue( Promise.resolve({version: '0.76.5'}), ); mockSleep.mockReturnValue(Promise.resolve()); await expect(async () => { await verifyPublishedTemplate('0.77.0', IS_LATEST, RETRIES); }).rejects.toThrowError('process.exit(1) called!'); expect(mockGetNpmPackageInfo).toHaveBeenCalledTimes(RETRIES); }); }); });