1- import { describe , expect , it , afterEach , jest } from '@jest/globals' ;
1+ import { afterEach , describe , expect , it , jest } from '@jest/globals' ;
22import fs from 'fs' ;
33import path from 'path' ;
44import { addGitObserver , catalogsToYaml , clearGitObservers , type Catalogs } from 'workspace-tools' ;
55import { generateChangeFiles , getChangeFiles } from '../__fixtures__/changeFiles' ;
66import { defaultBranchName , defaultRemoteBranchName } from '../__fixtures__/gitDefaults' ;
77import { initMockLogs } from '../__fixtures__/mockLogs' ;
8+ import { _mockNpmPublish , initNpmMock } from '../__fixtures__/mockNpm' ;
9+ import { deepFreezeProperties } from '../__fixtures__/object' ;
810import type { Repository } from '../__fixtures__/repository' ;
9- import { type PackageJsonFixture , type RepoFixture , RepositoryFactory } from '../__fixtures__/repositoryFactory' ;
11+ import { RepositoryFactory , type RepoFixture } from '../__fixtures__/repositoryFactory' ;
1012import { publish } from '../commands/publish' ;
13+ import { getPackageInfos } from '../monorepo/getPackageInfos' ;
14+ import { readJson } from '../object/readJson' ;
15+ import { getParsedOptions } from '../options/getOptions' ;
1116import type { ParsedOptions , RepoOptions } from '../types/BeachballOptions' ;
12- import { _mockNpmPublish , initNpmMock } from '../__fixtures__/mockNpm' ;
1317import type { PackageJson } from '../types/PackageInfo' ;
14- import { getParsedOptions } from '../options/getOptions' ;
15- import { getPackageInfos } from '../monorepo/getPackageInfos' ;
1618import { validate } from '../validation/validate' ;
17- import { readJson } from '../object/readJson' ;
18- import { createCommandContext } from '../monorepo/createCommandContext' ;
19- import { deepFreezeProperties } from '../__fixtures__/object' ;
2019
20+ // These tests are slow, so they should only cover E2E publishing scenarios that can't be fully
21+ // covered by lower-level tests (such as publishToRegistry functional tests), and a few all-up
22+ // scenarios as sanity checks. Tests specific to git or npm scenarios should potentially go in
23+ // publishGit.test.ts or publishRegistry.test.ts isntead.
24+ //
2125// Spawning actual npm to run commands against a fake registry is extremely slow, so mock it for
2226// this test (packagePublish covers the more complete npm registry scenario).
2327//
@@ -33,7 +37,7 @@ describe('publish command (e2e)', () => {
3337 let repo : Repository | undefined ;
3438
3539 // show error logs for these tests
36- const logs = initMockLogs ( { alsoLog : [ 'error' ] } ) ;
40+ initMockLogs ( { alsoLog : [ 'error' ] } ) ;
3741
3842 function getOptions ( repoOptions ?: Partial < RepoOptions > , extraArgv ?: string [ ] ) {
3943 const parsedOptions = getParsedOptions ( {
@@ -406,7 +410,8 @@ describe('publish command (e2e)', () => {
406410 } ) ;
407411 } ) ;
408412
409- // These tests are slow, so combine pre and post hooks
413+ // These tests are slow, so combine pre and post hooks.
414+ // This needs to be an E2E test to verify the versions etc passed through are correct.
410415 it ( 'respects prepublish/postpublish hooks' , async ( ) => {
411416 repositoryFactory = new RepositoryFactory ( 'monorepo' ) ;
412417 repo = repositoryFactory . cloneRepository ( ) ;
@@ -471,162 +476,4 @@ describe('publish command (e2e)', () => {
471476 expect ( fooJsonPost . customOnPublish ?. main ) . toBe ( 'lib/index.js' ) ;
472477 expect ( notified ) . toBe ( fooJsonPost . customAfterPublish ?. notify ) ;
473478 } ) ;
474-
475- it ( 'respects concurrency limit when publishing multiple packages' , async ( ) => {
476- const packagesToPublish = [ 'pkg1' , 'pkg2' , 'pkg3' , 'pkg4' , 'pkg5' ] ;
477- const packages : { [ packageName : string ] : PackageJsonFixture } = { } ;
478- for ( const name of packagesToPublish ) {
479- packages [ name ] = { version : '1.0.0' } ;
480- }
481-
482- repositoryFactory = new RepositoryFactory ( {
483- folders : {
484- packages : packages ,
485- } ,
486- } ) ;
487- repo = repositoryFactory . cloneRepository ( ) ;
488-
489- // Skip fetching and pushing since it's slow and not important for this test
490- const concurrency = 2 ;
491- const { options, parsedOptions } = getOptions ( { concurrency, fetch : false , push : false } ) ;
492- generateChangeFiles ( packagesToPublish , options ) ;
493-
494- const simulateWait = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
495-
496- let currentConcurrency = 0 ;
497- let maxConcurrency = 0 ;
498- npmMock . setCommandOverride ( 'publish' , async ( registryData , args , opts ) => {
499- currentConcurrency ++ ;
500- await simulateWait ( 100 ) ;
501- const result = await _mockNpmPublish ( registryData , args , opts ) ;
502- maxConcurrency = Math . max ( maxConcurrency , currentConcurrency ) ;
503- currentConcurrency -- ;
504- return result ;
505- } ) ;
506-
507- // skip validate for this test since it's not relevant
508- await publish ( options , createCommandContext ( parsedOptions ) ) ;
509- // Verify that at most `concurrency` number of packages were published concurrently
510- expect ( maxConcurrency ) . toBe ( concurrency ) ;
511-
512- // Verify all packages were published
513- for ( const pkg of packagesToPublish ) {
514- expect ( npmMock . getPublishedVersions ( pkg ) ) . toEqual ( {
515- versions : [ '1.1.0' ] ,
516- 'dist-tags' : { latest : '1.1.0' } ,
517- } ) ;
518- }
519- } ) ;
520-
521- it ( 'handles errors correctly when one package fails during concurrent publishing' , async ( ) => {
522- logs . setOverrideOptions ( { alsoLog : [ ] } ) ;
523- const packageNames = [ 'pkg1' , 'pkg2' , 'pkg3' , 'pkg4' , 'pkg5' ] ;
524- const packages : { [ packageName : string ] : PackageJsonFixture } = { } ;
525- const packageToFail = 'pkg3' ;
526- for ( const name of packageNames ) {
527- packages [ name ] = { version : '1.0.0' } ;
528- }
529- packages [ 'pkg1' ] . dependencies = { [ packageToFail ] : '1.0.0' } ;
530- packages [ 'pkg2' ] . dependencies = { [ packageToFail ] : '1.0.0' } ;
531-
532- repositoryFactory = new RepositoryFactory ( {
533- folders : { packages } ,
534- } ) ;
535- repo = repositoryFactory . cloneRepository ( ) ;
536-
537- const { options, parsedOptions } = getOptions ( {
538- concurrency : 3 ,
539- // Skip fetching and pushing since it's slow and not important for this test
540- fetch : false ,
541- push : false ,
542- } ) ;
543- generateChangeFiles ( packageNames , options ) ;
544-
545- npmMock . setCommandOverride ( 'publish' , async ( registryData , args , opts ) => {
546- if ( opts . cwd ?. endsWith ( packageToFail ) ) {
547- const stderr = 'Failed to publish package' ;
548- return { failed : true , stderr, stdout : '' , success : false , all : stderr } ;
549- }
550- return _mockNpmPublish ( registryData , args , opts ) ;
551- } ) ;
552-
553- // skip validate for this test since it's not relevant
554- await expect ( publish ( options , createCommandContext ( parsedOptions ) ) ) . rejects . toThrow (
555- 'Error publishing! Refer to the previous logs for recovery instructions.'
556- ) ;
557-
558- for ( const name of packageNames ) {
559- if ( [ 'pkg1' , 'pkg2' , packageToFail ] . includes ( name ) ) {
560- // Verify that the packages that failed to publish are not published.
561- // pkg1 and pkg2 are not published because they depend on pkg3, which failed to publish.
562- expect ( npmMock . getPublishedVersions ( name ) ) . toBeUndefined ( ) ;
563- } else {
564- // Verify that the packages that did not fail to publish are published
565- expect ( npmMock . getPublishedVersions ( name ) ) . toEqual ( {
566- versions : [ '1.1.0' ] ,
567- 'dist-tags' : { latest : '1.1.0' } ,
568- } ) ;
569- }
570- }
571- } ) ;
572-
573- // Just test postpublish (prepublish should have the same logic)
574- // TODO: possibly move to in-memory test
575- it ( 'respects concurrency limit for publish hooks' , async ( ) => {
576- const packagesToPublish = [ 'pkg1' , 'pkg2' , 'pkg3' , 'pkg4' ] ;
577- type ExtraPackageJsonFixture = PackageJsonFixture & { customAfterPublish ?: { notify : string } } ;
578- const packages : { [ packageName : string ] : ExtraPackageJsonFixture } = { } ;
579- for ( const name of packagesToPublish ) {
580- packages [ name ] = {
581- version : '1.0.0' ,
582- customAfterPublish : {
583- notify : `message-${ name } ` ,
584- } ,
585- } ;
586- }
587-
588- repositoryFactory = new RepositoryFactory ( {
589- folders : { packages } ,
590- } ) ;
591- repo = repositoryFactory . cloneRepository ( ) ;
592-
593- const simulateWait = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
594-
595- const afterPublishStrings : Record < string , string | undefined > = { } ;
596- const concurrency = 2 ;
597- let currentConcurrency = 0 ;
598- let maxConcurrency = 0 ;
599- const { options, parsedOptions } = getOptions ( {
600- hooks : {
601- postpublish : async ( packagePath , name ) => {
602- currentConcurrency ++ ;
603- await simulateWait ( 100 ) ;
604- const packageJsonPath = path . join ( packagePath , 'package.json' ) ;
605- const packageJson = readJson < ExtraPackageJsonFixture > ( packageJsonPath ) ;
606- afterPublishStrings [ name ] = packageJson . customAfterPublish ?. notify ;
607- maxConcurrency = Math . max ( maxConcurrency , currentConcurrency ) ;
608- currentConcurrency -- ;
609- } ,
610- } ,
611- concurrency,
612- // Skip fetching and pushing since it's slow and not important for this test
613- fetch : false ,
614- push : false ,
615- } ) ;
616-
617- generateChangeFiles ( packagesToPublish , options ) ;
618-
619- // skip validate for this test since it's not relevant
620- await publish ( options , createCommandContext ( parsedOptions ) ) ;
621- // Verify that at most `concurrency` number of postpublish hooks were running concurrently
622- expect ( maxConcurrency ) . toBe ( concurrency ) ;
623-
624- for ( const pkg of packagesToPublish ) {
625- const packageJson = readJson < ExtraPackageJsonFixture > ( repo . pathTo ( `packages/${ pkg } /package.json` ) ) ;
626- if ( packageJson . customAfterPublish ) {
627- // Verify that all postpublish hooks were called
628- expect ( afterPublishStrings [ pkg ] ) . toEqual ( packageJson . customAfterPublish . notify ) ;
629- }
630- }
631- } ) ;
632479} ) ;
0 commit comments