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 |
|
6 | import {resolve, parse} from 'path';
|
7 | import {
|
8 | copy,
|
9 | ensureDirSync,
|
10 | emptyDir,
|
11 | remove,
|
12 | ensureDir,
|
13 | pathExists,
|
14 | appendFile,
|
15 | } from 'fs-extra';
|
16 |
|
17 | /**
|
18 | * TestSandbox class provides a convenient way to get a reference to a
|
19 | * sandbox folder in which you can perform operations for testing purposes.
|
20 | */
|
21 | export class TestSandbox {
|
22 | // Path of the TestSandbox
|
23 | private _path?: string;
|
24 |
|
25 | public get path(): string {
|
26 | if (!this._path) {
|
27 | throw new Error(
|
28 | `TestSandbox instance was deleted. Create a new instance.`,
|
29 | );
|
30 | }
|
31 | return this._path;
|
32 | }
|
33 |
|
34 | /**
|
35 | * Will create a directory if it doesn't already exist. If it exists, you
|
36 | * still get an instance of the TestSandbox.
|
37 | *
|
38 | * @param path - Path of the TestSandbox. If relative (it will be resolved relative to cwd()).
|
39 | */
|
40 | constructor(path: string) {
|
41 | // resolve ensures path is absolute / makes it absolute (relative to cwd())
|
42 | this._path = resolve(path);
|
43 | ensureDirSync(this.path);
|
44 | }
|
45 |
|
46 | /**
|
47 | * Returns the path of the TestSandbox
|
48 | */
|
49 | getPath(): string {
|
50 | return this.path;
|
51 | }
|
52 |
|
53 | /**
|
54 | * Resets the TestSandbox. (Remove all files in it).
|
55 | */
|
56 | async reset(): Promise<void> {
|
57 | // Decache files from require's cache so future tests aren't affected incase
|
58 | // a file is recreated in sandbox with the same file name but different
|
59 | // contents after resetting the sandbox.
|
60 | for (const key in require.cache) {
|
61 | if (key.startsWith(this.path)) {
|
62 | delete require.cache[key];
|
63 | }
|
64 | }
|
65 |
|
66 | await emptyDir(this.path);
|
67 | }
|
68 |
|
69 | /**
|
70 | * Deletes the TestSandbox.
|
71 | */
|
72 | async delete(): Promise<void> {
|
73 | await remove(this.path);
|
74 | delete this._path;
|
75 | }
|
76 |
|
77 | /**
|
78 | * Makes a directory in the TestSandbox
|
79 | *
|
80 | * @param dir - Name of directory to create (relative to TestSandbox path)
|
81 | */
|
82 | async mkdir(dir: string): Promise<void> {
|
83 | await ensureDir(resolve(this.path, dir));
|
84 | }
|
85 |
|
86 | /**
|
87 | * Copies a file from src to the TestSandbox. If copying a `.js` file which
|
88 | * has an accompanying `.js.map` file in the src file location, the dest file
|
89 | * will have its sourceMappingURL updated to point to the original file as
|
90 | * an absolute path so you don't need to copy the map file.
|
91 | *
|
92 | * @param src - Absolute path of file to be copied to the TestSandbox
|
93 | * @param dest - Optional. Destination filename of the copy operation
|
94 | * (relative to TestSandbox). Original filename used if not specified.
|
95 | */
|
96 | async copyFile(src: string, dest?: string): Promise<void> {
|
97 | dest = dest
|
98 | ? resolve(this.path, dest)
|
99 | : resolve(this.path, parse(src).base);
|
100 |
|
101 | await copy(src, dest);
|
102 |
|
103 | if (parse(src).ext === '.js' && pathExists(src + '.map')) {
|
104 | const srcMap = src + '.map';
|
105 | await appendFile(dest, `\n//# sourceMappingURL=${srcMap}`);
|
106 | }
|
107 | }
|
108 | }
|