| 
1 |  | -import { expect, test } from '@rstest/core';  | 
2 |  | -import { mergeAliasWithTsConfigPaths, prettyTime } from '../src/utils';  | 
3 |  | - | 
4 |  | -test('should pretty time correctly', () => {  | 
5 |  | -  expect(prettyTime(0.0012)).toEqual('0.001 s');  | 
6 |  | -  expect(prettyTime(0.0123)).toEqual('0.01 s');  | 
7 |  | -  expect(prettyTime(0.1234)).toEqual('0.12 s');  | 
8 |  | -  expect(prettyTime(1.234)).toEqual('1.23 s');  | 
9 |  | -  expect(prettyTime(12.34)).toEqual('12.3 s');  | 
10 |  | -  expect(prettyTime(120)).toEqual('2 m');  | 
11 |  | -  expect(prettyTime(123.4)).toEqual('2 m 3.4 s');  | 
12 |  | -  expect(prettyTime(1234)).toEqual('20 m 34 s');  | 
13 |  | -  expect(prettyTime(1234.5)).toEqual('20 m 34.5 s');  | 
14 |  | -});  | 
 | 1 | +// import { execSync } from 'node:child_process';  | 
 | 2 | +import fs from 'node:fs/promises';  | 
 | 3 | +import path from 'node:path';  | 
 | 4 | +import { describe, expect, test } from '@rstest/core';  | 
 | 5 | +import {  | 
 | 6 | +  cleanTsBuildInfoFile,  | 
 | 7 | +  loadTsconfig,  | 
 | 8 | +  mergeAliasWithTsConfigPaths,  | 
 | 9 | +  prettyTime,  | 
 | 10 | +} from '../src/utils';  | 
15 | 11 | 
 
  | 
16 |  | -test('mergeAliasWithTsConfigPaths should handle empty inputs', () => {  | 
17 |  | -  // Both undefined  | 
18 |  | -  expect(  | 
19 |  | -    mergeAliasWithTsConfigPaths(undefined, undefined),  | 
20 |  | -  ).toMatchInlineSnapshot({}, '{}');  | 
21 |  | - | 
22 |  | -  // Empty objects  | 
23 |  | -  expect(mergeAliasWithTsConfigPaths({}, {})).toMatchInlineSnapshot({}, '{}');  | 
24 |  | - | 
25 |  | -  // One empty, one undefined  | 
26 |  | -  expect(mergeAliasWithTsConfigPaths({}, undefined)).toMatchInlineSnapshot(  | 
27 |  | -    {},  | 
28 |  | -    '{}',  | 
29 |  | -  );  | 
30 |  | -  expect(mergeAliasWithTsConfigPaths(undefined, {})).toMatchInlineSnapshot(  | 
31 |  | -    {},  | 
32 |  | -    '{}',  | 
33 |  | -  );  | 
 | 12 | +describe('prettyTime', () => {  | 
 | 13 | +  test('should pretty time correctly', () => {  | 
 | 14 | +    expect(prettyTime(0.0012)).toEqual('0.001 s');  | 
 | 15 | +    expect(prettyTime(0.0123)).toEqual('0.01 s');  | 
 | 16 | +    expect(prettyTime(0.1234)).toEqual('0.12 s');  | 
 | 17 | +    expect(prettyTime(1.234)).toEqual('1.23 s');  | 
 | 18 | +    expect(prettyTime(12.34)).toEqual('12.3 s');  | 
 | 19 | +    expect(prettyTime(120)).toEqual('2 m');  | 
 | 20 | +    expect(prettyTime(123.4)).toEqual('2 m 3.4 s');  | 
 | 21 | +    expect(prettyTime(1234)).toEqual('20 m 34 s');  | 
 | 22 | +    expect(prettyTime(1234.5)).toEqual('20 m 34.5 s');  | 
 | 23 | +  });  | 
34 | 24 | });  | 
35 | 25 | 
 
  | 
36 |  | -test('mergeAliasWithTsConfigPaths should handle paths only', () => {  | 
37 |  | -  const paths = {  | 
38 |  | -    '@/*': ['./src/*'],  | 
39 |  | -  };  | 
 | 26 | +describe('mergeAliasWithTsConfigPaths', () => {  | 
 | 27 | +  test('mergeAliasWithTsConfigPaths should handle empty inputs', () => {  | 
 | 28 | +    // Both undefined  | 
 | 29 | +    expect(  | 
 | 30 | +      mergeAliasWithTsConfigPaths(undefined, undefined),  | 
 | 31 | +    ).toMatchInlineSnapshot({}, '{}');  | 
40 | 32 | 
 
  | 
41 |  | -  const result = mergeAliasWithTsConfigPaths(paths, undefined);  | 
 | 33 | +    // Empty objects  | 
 | 34 | +    expect(mergeAliasWithTsConfigPaths({}, {})).toMatchInlineSnapshot({}, '{}');  | 
42 | 35 | 
 
  | 
43 |  | -  expect(result).toMatchInlineSnapshot(`  | 
44 |  | -    {  | 
45 |  | -      "@/*": [  | 
46 |  | -        "./src/*",  | 
47 |  | -      ],  | 
48 |  | -    }  | 
49 |  | -  `);  | 
50 |  | -});  | 
 | 36 | +    // One empty, one undefined  | 
 | 37 | +    expect(mergeAliasWithTsConfigPaths({}, undefined)).toMatchInlineSnapshot(  | 
 | 38 | +      {},  | 
 | 39 | +      '{}',  | 
 | 40 | +    );  | 
 | 41 | +    expect(mergeAliasWithTsConfigPaths(undefined, {})).toMatchInlineSnapshot(  | 
 | 42 | +      {},  | 
 | 43 | +      '{}',  | 
 | 44 | +    );  | 
 | 45 | +  });  | 
51 | 46 | 
 
  | 
52 |  | -test('mergeAliasWithTsConfigPaths should handle alias only', () => {  | 
53 |  | -  const alias = {  | 
54 |  | -    '@': './src',  | 
55 |  | -  };  | 
 | 47 | +  test('mergeAliasWithTsConfigPaths should handle paths only', () => {  | 
 | 48 | +    const paths = {  | 
 | 49 | +      '@/*': ['./src/*'],  | 
 | 50 | +    };  | 
56 | 51 | 
 
  | 
57 |  | -  const result = mergeAliasWithTsConfigPaths(undefined, alias);  | 
 | 52 | +    const result = mergeAliasWithTsConfigPaths(paths, undefined);  | 
58 | 53 | 
 
  | 
59 |  | -  expect(result).toMatchInlineSnapshot(`  | 
60 |  | -    {  | 
61 |  | -      "@": [  | 
62 |  | -        "./src",  | 
63 |  | -      ],  | 
64 |  | -    }  | 
65 |  | -  `);  | 
66 |  | -});  | 
 | 54 | +    expect(result).toMatchInlineSnapshot(`  | 
 | 55 | +      {  | 
 | 56 | +        "@/*": [  | 
 | 57 | +          "./src/*",  | 
 | 58 | +        ],  | 
 | 59 | +      }  | 
 | 60 | +    `);  | 
 | 61 | +  });  | 
67 | 62 | 
 
  | 
68 |  | -test('mergeAliasWithTsConfigPaths should handle alias overriding paths', () => {  | 
69 |  | -  const paths = {  | 
70 |  | -    '@utils/*': ['./lib/utils/*'],  | 
71 |  | -    '@/*': ['./src/*'],  | 
72 |  | -  };  | 
 | 63 | +  test('mergeAliasWithTsConfigPaths should handle alias only', () => {  | 
 | 64 | +    const alias = {  | 
 | 65 | +      '@': './src',  | 
 | 66 | +    };  | 
73 | 67 | 
 
  | 
74 |  | -  const alias = {  | 
75 |  | -    '@utils/*': './src/utils',  | 
76 |  | -    '@components': './src/components',  | 
77 |  | -  };  | 
 | 68 | +    const result = mergeAliasWithTsConfigPaths(undefined, alias);  | 
78 | 69 | 
 
  | 
79 |  | -  const result = mergeAliasWithTsConfigPaths(paths, alias);  | 
80 |  | - | 
81 |  | -  expect(Object.keys(result)).toMatchInlineSnapshot(`  | 
82 |  | -    [  | 
83 |  | -      "@utils/*",  | 
84 |  | -      "@components",  | 
85 |  | -      "@/*",  | 
86 |  | -    ]  | 
87 |  | -  `);  | 
88 |  | -  expect(Object.values(result)).toMatchInlineSnapshot(`  | 
89 |  | -    [  | 
90 |  | -      [  | 
91 |  | -        "./src/utils",  | 
92 |  | -      ],  | 
 | 70 | +    expect(result).toMatchInlineSnapshot(`  | 
 | 71 | +      {  | 
 | 72 | +        "@": [  | 
 | 73 | +          "./src",  | 
 | 74 | +        ],  | 
 | 75 | +      }  | 
 | 76 | +    `);  | 
 | 77 | +  });  | 
 | 78 | + | 
 | 79 | +  test('mergeAliasWithTsConfigPaths should handle alias overriding paths', () => {  | 
 | 80 | +    const paths = {  | 
 | 81 | +      '@utils/*': ['./lib/utils/*'],  | 
 | 82 | +      '@/*': ['./src/*'],  | 
 | 83 | +    };  | 
 | 84 | + | 
 | 85 | +    const alias = {  | 
 | 86 | +      '@utils/*': './src/utils',  | 
 | 87 | +      '@components': './src/components',  | 
 | 88 | +    };  | 
 | 89 | + | 
 | 90 | +    const result = mergeAliasWithTsConfigPaths(paths, alias);  | 
 | 91 | + | 
 | 92 | +    expect(Object.keys(result)).toMatchInlineSnapshot(`  | 
93 | 93 |       [  | 
94 |  | -        "./src/components",  | 
95 |  | -      ],  | 
 | 94 | +        "@utils/*",  | 
 | 95 | +        "@components",  | 
 | 96 | +        "@/*",  | 
 | 97 | +      ]  | 
 | 98 | +    `);  | 
 | 99 | +    expect(Object.values(result)).toMatchInlineSnapshot(`  | 
96 | 100 |       [  | 
97 |  | -        "./src/*",  | 
98 |  | -      ],  | 
99 |  | -    ]  | 
100 |  | -  `);  | 
 | 101 | +        [  | 
 | 102 | +          "./src/utils",  | 
 | 103 | +        ],  | 
 | 104 | +        [  | 
 | 105 | +          "./src/components",  | 
 | 106 | +        ],  | 
 | 107 | +        [  | 
 | 108 | +          "./src/*",  | 
 | 109 | +        ],  | 
 | 110 | +      ]  | 
 | 111 | +    `);  | 
 | 112 | +  });  | 
 | 113 | +});  | 
 | 114 | + | 
 | 115 | +describe('cleanTsBuildInfoFile', () => {  | 
 | 116 | +  const fileExists = async (filePath: string): Promise<boolean> => {  | 
 | 117 | +    try {  | 
 | 118 | +      await fs.access(filePath);  | 
 | 119 | +      return true;  | 
 | 120 | +    } catch {  | 
 | 121 | +      return false;  | 
 | 122 | +    }  | 
 | 123 | +  };  | 
 | 124 | + | 
 | 125 | +  const testCases = [  | 
 | 126 | +    {  | 
 | 127 | +      name: 'default config without custom tsBuildInfoFile',  | 
 | 128 | +      config: { composite: true },  | 
 | 129 | +      expectedPath: 'tsconfig.case1.tsbuildinfo',  | 
 | 130 | +    },  | 
 | 131 | +    {  | 
 | 132 | +      name: 'custom tsBuildInfoFile path',  | 
 | 133 | +      config: {  | 
 | 134 | +        composite: true,  | 
 | 135 | +        tsBuildInfoFile: 'node_modules/.cache/tsconfig.case2.tsbuildinfo',  | 
 | 136 | +      },  | 
 | 137 | +      expectedPath: 'node_modules/.cache/tsconfig.case2.tsbuildinfo',  | 
 | 138 | +    },  | 
 | 139 | +    {  | 
 | 140 | +      name: 'outDir without rootDir',  | 
 | 141 | +      config: { composite: true, outDir: 'dist3' },  | 
 | 142 | +      expectedPath: 'dist3/tsconfig.case3.tsbuildinfo',  | 
 | 143 | +    },  | 
 | 144 | +    {  | 
 | 145 | +      name: 'outDir with rootDir',  | 
 | 146 | +      config: { composite: true, outDir: 'dist4', rootDir: 'src' },  | 
 | 147 | +      expectedPath: 'tsconfig.case4.tsbuildinfo',  | 
 | 148 | +    },  | 
 | 149 | +    {  | 
 | 150 | +      name: 'nested outDir with rootDir',  | 
 | 151 | +      config: { composite: true, outDir: 'dist/5', rootDir: 'src' },  | 
 | 152 | +      expectedPath: 'dist/tsconfig.case5.tsbuildinfo',  | 
 | 153 | +    },  | 
 | 154 | +  ];  | 
 | 155 | + | 
 | 156 | +  test('should clean tsBuildInfo files for various tsconfig configurations', async () => {  | 
 | 157 | +    delete process.env.NO_COLOR;  | 
 | 158 | +    const tempDir = await fs.mkdtemp(path.join(__dirname, 'temp-test-'));  | 
 | 159 | + | 
 | 160 | +    const srcPath = path.join(tempDir, 'src/index.ts');  | 
 | 161 | +    await fs.mkdir(path.dirname(srcPath), { recursive: true });  | 
 | 162 | +    await fs.writeFile(srcPath, 'export {}');  | 
 | 163 | + | 
 | 164 | +    try {  | 
 | 165 | +      await Promise.all(  | 
 | 166 | +        testCases.map(async (testCase, index) => {  | 
 | 167 | +          const caseNumber = index + 1;  | 
 | 168 | +          const tsconfigPath = path.join(  | 
 | 169 | +            tempDir,  | 
 | 170 | +            `tsconfig.case${caseNumber}.json`,  | 
 | 171 | +          );  | 
 | 172 | +          const expectedBuildInfoPath = path.join(  | 
 | 173 | +            tempDir,  | 
 | 174 | +            testCase.expectedPath,  | 
 | 175 | +          );  | 
 | 176 | + | 
 | 177 | +          await fs.writeFile(  | 
 | 178 | +            tsconfigPath,  | 
 | 179 | +            JSON.stringify({ compilerOptions: testCase.config }, null, 2),  | 
 | 180 | +          );  | 
 | 181 | + | 
 | 182 | +          // execSync(`npx tsc --p ${tsconfigPath}`, { cwd: tempDir });  | 
 | 183 | +          // tsc is too slow, so we directly create the file  | 
 | 184 | +          await fs.mkdir(path.dirname(expectedBuildInfoPath), {  | 
 | 185 | +            recursive: true,  | 
 | 186 | +          });  | 
 | 187 | +          await fs.writeFile(  | 
 | 188 | +            path.join(tempDir, testCase.expectedPath),  | 
 | 189 | +            'Generated tsBuildInfo content',  | 
 | 190 | +          );  | 
 | 191 | + | 
 | 192 | +          expect(await fileExists(expectedBuildInfoPath)).toBe(true);  | 
 | 193 | + | 
 | 194 | +          const tsconfig = loadTsconfig(tsconfigPath);  | 
 | 195 | +          await cleanTsBuildInfoFile(tsconfigPath, tsconfig.options);  | 
 | 196 | + | 
 | 197 | +          expect(await fileExists(expectedBuildInfoPath)).toBe(false);  | 
 | 198 | +        }),  | 
 | 199 | +      );  | 
 | 200 | +    } finally {  | 
 | 201 | +      await fs.rm(tempDir, { recursive: true, force: true });  | 
 | 202 | +    }  | 
 | 203 | +  });  | 
101 | 204 | });  | 
0 commit comments