go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/testing_tools/jest_utils.ts (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import * as path from 'path'; 16 17 import callsites from 'callsites'; 18 19 /** 20 * Resolves a module in the specified file. 21 */ 22 function resolveModuleInFile(moduleName: string, filename: string): string { 23 if (!moduleName.startsWith('.')) { 24 return moduleName; 25 } 26 27 return path.join(path.dirname(filename), moduleName); 28 } 29 30 /** 31 * See the type definition for `self.createSelectiveMockFromModule`. 32 */ 33 export function createSelectiveMockFromModule<T = unknown>( 34 moduleName: string, 35 keysToMock: ReadonlyArray<keyof NoInfer<T>>, 36 ): T { 37 // Resolve the module at the caller site. 38 // This allows the caller to mock a module with a relative path. 39 moduleName = resolveModuleInFile(moduleName, callsites()[1].getFileName()!); 40 const actualModule = jest.requireActual(moduleName); 41 const mockedModule = jest.createMockFromModule(moduleName) as T; 42 43 return { 44 ...actualModule, 45 ...Object.fromEntries(keysToMock.map((k) => [k, mockedModule[k]])), 46 }; 47 } 48 49 /** 50 * See the type definition for `self.createSelectiveSpiesFromModule`. 51 */ 52 export function createSelectiveSpiesFromModule<T = unknown>( 53 moduleName: string, 54 keysToSpy: ReadonlyArray<FunctionKeys<NoInfer<T>>>, 55 ): T { 56 // Resolve the module at the caller site. 57 // This allows the caller to mock a module with a relative path. 58 moduleName = resolveModuleInFile(moduleName, callsites()[1].getFileName()!); 59 const actualModule = jest.requireActual(moduleName); 60 return { 61 ...actualModule, 62 ...Object.fromEntries(keysToSpy.map((k) => [k, jest.fn(actualModule[k])])), 63 }; 64 }