UNPKG

3.91 kBPlain TextView Raw
1// Copyright IBM Corp. 2018. All Rights Reserved.
2// Node module: @loopback/testlab
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6import {
7 appendFile,
8 copy,
9 emptyDir,
10 ensureDir,
11 ensureDirSync,
12 pathExists,
13 remove,
14 writeFile,
15 writeJson,
16} from 'fs-extra';
17import {parse, resolve} from 'path';
18
19/**
20 * TestSandbox class provides a convenient way to get a reference to a
21 * sandbox folder in which you can perform operations for testing purposes.
22 */
23export class TestSandbox {
24 // Path of the TestSandbox
25 private _path?: string;
26
27 public get path(): string {
28 if (!this._path) {
29 throw new Error(
30 `TestSandbox instance was deleted. Create a new instance.`,
31 );
32 }
33 return this._path;
34 }
35
36 /**
37 * Will create a directory if it doesn't already exist. If it exists, you
38 * still get an instance of the TestSandbox.
39 *
40 * @param path - Path of the TestSandbox. If relative (it will be resolved relative to cwd()).
41 */
42 constructor(path: string) {
43 // resolve ensures path is absolute / makes it absolute (relative to cwd())
44 this._path = resolve(path);
45 ensureDirSync(this.path);
46 }
47
48 /**
49 * Returns the path of the TestSandbox
50 */
51 getPath(): string {
52 return this.path;
53 }
54
55 /**
56 * Resets the TestSandbox. (Remove all files in it).
57 */
58 async reset(): Promise<void> {
59 // Decache files from require's cache so future tests aren't affected incase
60 // a file is recreated in sandbox with the same file name but different
61 // contents after resetting the sandbox.
62 for (const key in require.cache) {
63 if (key.startsWith(this.path)) {
64 delete require.cache[key];
65 }
66 }
67
68 await emptyDir(this.path);
69 }
70
71 /**
72 * Deletes the TestSandbox.
73 */
74 async delete(): Promise<void> {
75 await remove(this.path);
76 delete this._path;
77 }
78
79 /**
80 * Makes a directory in the TestSandbox
81 *
82 * @param dir - Name of directory to create (relative to TestSandbox path)
83 */
84 async mkdir(dir: string): Promise<void> {
85 await ensureDir(resolve(this.path, dir));
86 }
87
88 /**
89 * Copies a file from src to the TestSandbox. If copying a `.js` file which
90 * has an accompanying `.js.map` file in the src file location, the dest file
91 * will have its sourceMappingURL updated to point to the original file as
92 * an absolute path so you don't need to copy the map file.
93 *
94 * @param src - Absolute path of file to be copied to the TestSandbox
95 * @param dest - Optional. Destination filename of the copy operation
96 * (relative to TestSandbox). Original filename used if not specified.
97 */
98 async copyFile(src: string, dest?: string): Promise<void> {
99 dest = dest
100 ? resolve(this.path, dest)
101 : resolve(this.path, parse(src).base);
102
103 await copy(src, dest);
104
105 if (parse(src).ext === '.js' && pathExists(src + '.map')) {
106 const srcMap = src + '.map';
107 await appendFile(dest, `\n//# sourceMappingURL=${srcMap}`);
108 }
109 }
110
111 /**
112 * Creates a new file and writes the given data serialized as JSON.
113 *
114 * @param dest - Destination filename, optionally including a relative path.
115 * @param data - The data to write.
116 */
117 async writeJsonFile(dest: string, data: unknown): Promise<void> {
118 dest = resolve(this.path, dest);
119 const destDir = parse(dest).dir;
120 await ensureDir(destDir);
121 return writeJson(dest, data, {spaces: 2});
122 }
123
124 /**
125 * Creates a new file and writes the given data as a UTF-8-encoded text.
126 *
127 * @param dest - Destination filename, optionally including a relative path.
128 * @param data - The text to write.
129 */
130 async writeTextFile(dest: string, data: string): Promise<void> {
131 dest = resolve(this.path, dest);
132 const destDir = parse(dest).dir;
133 await ensureDir(destDir);
134 return writeFile(dest, data, {encoding: 'utf-8'});
135 }
136}