Skip to content

Commit

Permalink
Sort Postman folders based on the "orderOfFolders" configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
thim81 committed Aug 21, 2024
1 parent 5dea1dd commit 3971167
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## [Unreleased]

- Portman - sort Postman folders based on the "orderOfFolders" configuration

## v1.29.3 - (2024-08-19)

- Portman - Make OpenAPI data immutable (#630)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ The configuration defined in the `globals` will be executed on the full Postman
- **portmanReplacements** : The "search & replace" utility right before the final Postman file is written, that will search a string/object/... and replace it with another string/object/...
This is practical to replace any data from the generated Portman collection, before it is used in Postman / Newman test execution.
- **orderOfOperations** : The `orderOfOperations` is a list of OpenAPI operations, which is used by Portman to sort the Postman requests in the desired order, in their folder. The ordering from `orderOfOperations` is performed per folder. Items that are **not** defined in the `orderOfOperations` list will remain at their current order.
- **orderOfFolders** : The `orderOfFolders` is a list of Postman folder names, which is used by Portman to sort the Postman folders in the desired order. Folders that are **not** defined in the `orderOfFolders` list will remain at their current order, after the re-order folders.
- **securityOverwrites** : Overwrite of the OpenAPI Security Scheme Object (supported types: "apiKey", "http basic auth", "http bearer token") or inject a Postman authorization option (supported types: awsv4, digest, edgegrid, ntlm, oauth1, oauth2) on a collection level.

The security overwrites provides a number of security types:
Expand Down
11 changes: 9 additions & 2 deletions src/application/CollectionWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
overwriteCollectionSecurityValues,
writeCollectionPreRequestScripts,
writeCollectionVariables,
writeRawReplacements
writeRawReplacements,
orderCollectionFolders
} from '.'
import { GlobalConfig, PortmanConfig, PortmanOptions } from '../types'
import { isEmptyObject } from '../utils'
Expand Down Expand Up @@ -36,7 +37,8 @@ export class CollectionWriter {
keyValueReplacements = {},
valueReplacements = {},
rawReplacements = [],
orderOfOperations = []
orderOfOperations = [],
orderOfFolders = []
} = globals as GlobalConfig

let collection = this.collection
Expand Down Expand Up @@ -71,6 +73,11 @@ export class CollectionWriter {
collection = orderCollectionRequests(collection, orderOfOperations)
}

// --- Portman - Set manually order Postman folders
if (orderOfFolders && orderOfFolders.length > 0) {
collection = orderCollectionFolders(collection, orderOfFolders)
}

// --- Portman - Set Postman collection pre-requests scripts
if (collectionPreRequestScripts && collectionPreRequestScripts.length > 0) {
collection = writeCollectionPreRequestScripts(collection, collectionPreRequestScripts)
Expand Down
1 change: 1 addition & 0 deletions src/application/globals/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './injectEnvVariables'
export * from './orderCollectionFolders'
export * from './orderCollectionRequests'
export * from './overwriteCollectionKeyValues'
export * from './overwriteCollectionSecurityValues'
Expand Down
77 changes: 77 additions & 0 deletions src/application/globals/orderCollectionFolders.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { orderCollectionFolders } from '../../application'

describe('orderCollectionFolders()', () => {
it('should order the postman request items in folder in the order like defined', () => {
const order = ['Folder D', 'Folder B']
const obj = {
info: {
name: 'Test Collection',
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
},
item: [
{
name: 'Folder A',
item: [
{
name: 'Request A1',
request: {
url: 'https://example.com',
method: 'GET'
}
}
]
},
{
name: 'Folder B',
item: [
{
name: 'Request B1',
request: {
url: 'https://example.com',
method: 'POST'
}
}
]
},
{
name: 'Folder C',
item: [
{
name: 'Request C1',
request: {
url: 'https://example.com',
method: 'PUT'
}
}
]
},
{
name: 'Folder D',
item: [
{
name: 'Request D1',
request: {
url: 'https://example.com',
method: 'DELETE'
}
}
]
},
{
name: 'Root Request',
request: {
url: 'https://example.com/root',
method: 'HEAD'
}
}
]
}

const transform = orderCollectionFolders(obj, order)
expect(transform.item[0].name).toBe('Folder D') // First in the desired order
expect(transform.item[1].name).toBe('Folder B') // Second in the desired order
expect(transform.item[2].name).toBe('Folder A') // Original position, not reordered
expect(transform.item[3].name).toBe('Folder C') // Original position, not reordered
expect(transform.item[4].name).toBe('Root Request')
})
})
47 changes: 47 additions & 0 deletions src/application/globals/orderCollectionFolders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any */
import { Collection, Item, ItemGroup } from 'postman-collection'

export const orderCollectionFolders = (obj: any, orderOfFolders: any = []): any => {
// Convert the input object to a Postman Collection instance if it isn't already
const collection = obj instanceof Collection ? obj : new Collection(obj)

// Arrays to hold folders and non-folder items
const folders: ItemGroup<Item>[] = []
const nonFolderItems: Item[] = []

// Iterate over the collection items to categorize them
collection.items.each(item => {
if (ItemGroup.isItemGroup(item)) {
folders.push(item as ItemGroup<Item>)
} else {
nonFolderItems.push(item as Item)
}
})

// Create a map for quick lookup of folder indexes by name
const folderMap = new Map(folders.map((folder, index) => [folder.name, index]))

// Sort folders based on the order provided
const sortedFolders = orderOfFolders
.map(name => folderMap.get(name)) // get the index of the folder by name
.filter(index => index !== undefined) // filter out undefined (non-existent folders in the order list)
.map(index => folders[index] as ItemGroup<Item>) // map to the actual folder items

// Append remaining folders that were not in the orderOfFolders list
const remainingFolders = folders.filter(folder => !orderOfFolders.includes(folder.name))

// Combine the sorted and remaining folders
const orderedFolders = [...sortedFolders, ...remainingFolders]

// Clear the collection items
collection.items.clear()

// Add the sorted folders back to the collection
orderedFolders.forEach(folder => collection.items.add(folder))

// Append the non-folder root items back to the collection
nonFolderItems.forEach(item => collection.items.add(item))

const collectionObj = JSON.parse(JSON.stringify(collection))
return collectionObj
}
1 change: 1 addition & 0 deletions src/types/PortmanConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ export type GlobalConfig = {
rawReplacements?: GlobalReplacement[]
portmanReplacements?: GlobalReplacement[]
orderOfOperations?: string[]
orderOfFolders?: string[]
stripResponseExamples?: boolean
variableCasing?:
| 'camelCase'
Expand Down
6 changes: 6 additions & 0 deletions src/utils/portman-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
},
"type": "array"
},
"orderOfFolders": {
"items": {
"type": "string"
},
"type": "array"
},
"portmanReplacements": {
"items": {
"additionalProperties": false,
Expand Down

0 comments on commit 3971167

Please sign in to comment.