diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index 5274b49ce2..bc78e2b4e0 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -50,6 +50,7 @@ "@backstage/types": "workspace:^", "better-sqlite3": "^8.0.0", "express": "^4.17.1", + "fs-extra": "^10.0.1", "knex": "^2.0.0", "msw": "^1.0.0", "mysql2": "^2.2.5", diff --git a/packages/backend-test-utils/src/files/DirectoryMocker.ts b/packages/backend-test-utils/src/files/DirectoryMocker.ts new file mode 100644 index 0000000000..6b67f8f9c0 --- /dev/null +++ b/packages/backend-test-utils/src/files/DirectoryMocker.ts @@ -0,0 +1,83 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { resolveSafeChildPath } from '@backstage/backend-common'; +import fs from 'fs-extra'; +import { tmpdir as getTmpDir } from 'os'; +import { join as joinPath } from 'path'; + +type FileNode = string | Buffer; + +type DirectoryNode = { + [name in string]: MockDirectoryNode; +}; + +type MockDirectoryNode = DirectoryNode | FileNode; + +export class DirectoryMocker { + static create() { + const root = fs.mkdtempSync( + joinPath(getTmpDir(), 'backstage-tmp-test-dir-'), + ); + + const mocker = new DirectoryMocker(root); + + process.on('beforeExit', mocker.#cleanupSync); + + afterAll(async () => { + await mocker.cleanup(); + }); + + return mocker; + } + + readonly #root: string; + + private constructor(root: string) { + this.#root = root; + } + + get dir() { + return this.#root; + } + + async setContent(root: MockDirectoryNode) { + await this.cleanup(); + + async function createFiles(node: MockDirectoryNode, path: string) { + if (typeof node === 'string' || node instanceof Buffer) { + await fs.writeFile(path, node, 'utf8'); + return; + } + + await fs.ensureDir(path); + + for (const [name, child] of Object.entries(node)) { + await createFiles(child, resolveSafeChildPath(path, name)); + } + } + + await createFiles(root, this.#root); + } + + async cleanup() { + await fs.rm(this.#root, { recursive: true, force: true }); + } + + #cleanupSync() { + fs.rmSync(this.#root, { recursive: true, force: true }); + } +} diff --git a/packages/backend-test-utils/src/files/index.ts b/packages/backend-test-utils/src/files/index.ts new file mode 100644 index 0000000000..f6ed111069 --- /dev/null +++ b/packages/backend-test-utils/src/files/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DirectoryMocker } from './DirectoryMocker'; diff --git a/packages/backend-test-utils/src/index.ts b/packages/backend-test-utils/src/index.ts index ae937d2fc8..5609dbbc2b 100644 --- a/packages/backend-test-utils/src/index.ts +++ b/packages/backend-test-utils/src/index.ts @@ -22,5 +22,6 @@ export * from './database'; export * from './msw'; +export * from './files'; export * from './next'; export * from './util'; diff --git a/yarn.lock b/yarn.lock index 9419064a2e..83d9128534 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3649,6 +3649,7 @@ __metadata: "@types/supertest": ^2.0.8 better-sqlite3: ^8.0.0 express: ^4.17.1 + fs-extra: ^10.0.1 knex: ^2.0.0 msw: ^1.0.0 mysql2: ^2.2.5