Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 73 lines 2.9 kB view raw
1// eslint-disable-next-line import/no-extraneous-dependencies 2import jestSnapshot from 'jest-snapshot'; 3import { JSONPath } from 'jsonpath-plus'; 4import lodash from 'lodash'; 5 6const { toMatchSnapshot } = jestSnapshot; 7const { set } = lodash; 8 9interface CustomMatchers<R = unknown> { 10 /** 11 * This assertion works like `toMatchSnapshot`, except that it makes it 12 * easier to define many asymmetric property matchers at once, to better 13 * support cases where many keys in the snapshot have dynamic values. 14 * 15 * For example, the data being snapshotted might be a list of newly-created 16 * objects, each of which has a dynamically-generated id. In that case, you 17 * could use this assertion to easily require that every id is a string: 18 * 19 * `toMatchDynamicSnapshot({ '$[*].id': expect.any(String) })`. 20 * 21 * In the above, the `$[*].id` key is a jsonpath expression that matches the 22 * id property of every object in the root list. 23 */ 24 toMatchDynamicSnapshot(propertyMatchers: object, hint?: string): R; 25} 26 27declare global { 28 // eslint-disable-next-line @typescript-eslint/no-namespace 29 namespace jest { 30 // Normally, an empty interface in TS is pointless but, in this case, we're 31 // actually taking advantage of declaration merging (on Expect, Matchers, 32 // and InverseAsymmetricMatchers) to make those interfaces, which are defined 33 // elsewhere extend our CustomMatchers interface. 34 // eslint-disable-next-line @typescript-eslint/no-empty-object-type 35 interface Expect extends CustomMatchers {} 36 // eslint-disable-next-line @typescript-eslint/no-empty-object-type 37 interface Matchers<R> extends CustomMatchers<R> {} 38 // eslint-disable-next-line @typescript-eslint/no-empty-object-type 39 interface InverseAsymmetricMatchers extends CustomMatchers {} 40 } 41} 42 43expect.extend({ 44 toMatchDynamicSnapshot(received, propertyMatchers: object, hint?: string) { 45 // Treat property matcher keys as jsonpath queries 46 // if they start with a $ and contain a dot. 47 const isJsonPath = (it: string) => it[0] === '$' && it.includes('.'); 48 const generatedPropertyMatchers = { ...propertyMatchers }; 49 50 Object.keys(propertyMatchers).forEach((k) => { 51 const key = k as keyof typeof generatedPropertyMatchers & 52 keyof typeof propertyMatchers; 53 54 if (isJsonPath(k)) { 55 // eslint-disable-next-line @typescript-eslint/no-dynamic-delete, functional/immutable-data -- derived snapshot matchers 56 delete generatedPropertyMatchers[key]; 57 JSONPath({ path: k, json: received, resultType: 'path' }).forEach( 58 (pathStr: string) => { 59 const path = JSONPath.toPathArray(pathStr).slice(1); 60 set(generatedPropertyMatchers, path, propertyMatchers[key]); 61 }, 62 ); 63 } 64 }); 65 66 return (toMatchSnapshot as any).call( 67 this, 68 received, 69 generatedPropertyMatchers, 70 hint, 71 ); 72 }, 73});