22const {
33 SafeMap,
44} = primordials ;
5+ const {
6+ codes : {
7+ ERR_INVALID_ARG_TYPE ,
8+ } ,
9+ } = require ( 'internal/errors' ) ;
510const {
611 validateFunction,
12+ validateInteger,
713 validateString,
814} = require ( 'internal/validators' ) ;
15+ const { isDeepStrictEqual } = require ( 'internal/util/comparisons' ) ;
916const assert = require ( 'assert' ) ;
17+ const { AssertionError } = assert ;
1018const methodsToCopy = [
1119 'deepEqual' ,
1220 'deepStrictEqual' ,
@@ -28,13 +36,110 @@ const methodsToCopy = [
2836] ;
2937let assertMap ;
3038
39+ function getMockContext ( fn ) {
40+ const { MockFunctionContext } = require ( 'internal/test_runner/mock/mock' ) ;
41+ const ctx = fn ?. mock ;
42+
43+ if ( ! ( ctx instanceof MockFunctionContext ) ) {
44+ throw new ERR_INVALID_ARG_TYPE ( 'fn' , 'mock function' , fn ) ;
45+ }
46+
47+ return ctx ;
48+ }
49+
50+ function called ( fn , message ) {
51+ const count = getMockContext ( fn ) . callCount ( ) ;
52+
53+ if ( count === 0 ) {
54+ throw new AssertionError ( {
55+ __proto__ : null ,
56+ message : message ?? 'Expected mock function to have been called' ,
57+ actual : count ,
58+ operator : 'called' ,
59+ stackStartFn : called ,
60+ } ) ;
61+ }
62+ }
63+
64+ function callCount ( fn , times , message ) {
65+ validateInteger ( times , 'times' , 0 ) ;
66+ const count = getMockContext ( fn ) . callCount ( ) ;
67+
68+ if ( count !== times ) {
69+ throw new AssertionError ( {
70+ __proto__ : null ,
71+ message : message ??
72+ `Expected mock function to have been called ${ times } times, but it was called ${ count } times` ,
73+ actual : count ,
74+ expected : times ,
75+ operator : 'callCount' ,
76+ stackStartFn : callCount ,
77+ } ) ;
78+ }
79+ }
80+
81+ function assertCalledWithAt ( fn , n , args , stackStartFn ) {
82+ const calls = getMockContext ( fn ) . calls ;
83+
84+ if ( n > calls . length ) {
85+ throw new AssertionError ( {
86+ __proto__ : null ,
87+ message : `Expected mock function to have been called at least ${ n } times, ` +
88+ `but it was called ${ calls . length } times` ,
89+ actual : calls . length ,
90+ expected : n ,
91+ operator : stackStartFn . name ,
92+ stackStartFn,
93+ } ) ;
94+ }
95+
96+ const actual = calls [ n - 1 ] . arguments ;
97+
98+ if ( ! isDeepStrictEqual ( actual , args ) ) {
99+ throw new AssertionError ( {
100+ __proto__ : null ,
101+ message : `Expected call ${ n } of mock function to have been called with:` ,
102+ actual,
103+ expected : args ,
104+ operator : 'deepStrictEqual' ,
105+ stackStartFn,
106+ } ) ;
107+ }
108+ }
109+
110+ function nthCalledWith ( fn , n , ...args ) {
111+ validateInteger ( n , 'n' , 1 ) ;
112+ assertCalledWithAt ( fn , n , args , nthCalledWith ) ;
113+ }
114+
115+ function lastCalledWith ( fn , ...args ) {
116+ const count = getMockContext ( fn ) . callCount ( ) ;
117+
118+ if ( count === 0 ) {
119+ throw new AssertionError ( {
120+ __proto__ : null ,
121+ message : 'Expected mock function to have been called' ,
122+ actual : count ,
123+ operator : 'lastCalledWith' ,
124+ stackStartFn : lastCalledWith ,
125+ } ) ;
126+ }
127+
128+ assertCalledWithAt ( fn , count , args , lastCalledWith ) ;
129+ }
130+
31131function getAssertionMap ( ) {
32132 if ( assertMap === undefined ) {
33133 assertMap = new SafeMap ( ) ;
34134
35135 for ( let i = 0 ; i < methodsToCopy . length ; i ++ ) {
36136 assertMap . set ( methodsToCopy [ i ] , assert [ methodsToCopy [ i ] ] ) ;
37137 }
138+
139+ assertMap . set ( 'called' , called ) ;
140+ assertMap . set ( 'callCount' , callCount ) ;
141+ assertMap . set ( 'lastCalledWith' , lastCalledWith ) ;
142+ assertMap . set ( 'nthCalledWith' , nthCalledWith ) ;
38143 }
39144
40145 return assertMap ;
0 commit comments