|
2 | 2 | const common = require('../common');
|
3 | 3 | const assert = require('node:assert');
|
4 | 4 | const { mock, test } = require('node:test');
|
5 |
| - |
6 | 5 | test('spies on a function', (t) => {
|
7 | 6 | const sum = t.mock.fn((arg1, arg2) => {
|
8 | 7 | return arg1 + arg2;
|
@@ -319,6 +318,157 @@ test('spy functions can be bound', (t) => {
|
319 | 318 | assert.strictEqual(sum.bind(0)(2, 11), 13);
|
320 | 319 | });
|
321 | 320 |
|
| 321 | +test('mocks prototype methods on an instance', async (t) => { |
| 322 | + class Runner { |
| 323 | + async someTask(msg) { |
| 324 | + return Promise.resolve(msg); |
| 325 | + } |
| 326 | + |
| 327 | + async method(msg) { |
| 328 | + await this.someTask(msg); |
| 329 | + return msg; |
| 330 | + } |
| 331 | + } |
| 332 | + const msg = 'ok'; |
| 333 | + const obj = new Runner(); |
| 334 | + assert.strictEqual(await obj.method(msg), msg); |
| 335 | + |
| 336 | + t.mock.method(obj, obj.someTask.name); |
| 337 | + assert.strictEqual(obj.someTask.mock.calls.length, 0); |
| 338 | + |
| 339 | + assert.strictEqual(await obj.method(msg), msg); |
| 340 | + |
| 341 | + const call = obj.someTask.mock.calls[0]; |
| 342 | + |
| 343 | + assert.deepStrictEqual(call.arguments, [msg]); |
| 344 | + assert.strictEqual(await call.result, msg); |
| 345 | + assert.strictEqual(call.target, undefined); |
| 346 | + assert.strictEqual(call.this, obj); |
| 347 | + |
| 348 | + const obj2 = new Runner(); |
| 349 | + // Ensure that a brand new instance is not mocked |
| 350 | + assert.strictEqual( |
| 351 | + obj2.someTask.mock, |
| 352 | + undefined |
| 353 | + ); |
| 354 | + |
| 355 | + assert.strictEqual(obj.someTask.mock.restore(), undefined); |
| 356 | + assert.strictEqual(await obj.method(msg), msg); |
| 357 | + assert.strictEqual(obj.someTask.mock, undefined); |
| 358 | + assert.strictEqual(Runner.prototype.someTask.mock, undefined); |
| 359 | +}); |
| 360 | + |
| 361 | +test('spies on async static class methods', async (t) => { |
| 362 | + class Runner { |
| 363 | + static async someTask(msg) { |
| 364 | + return Promise.resolve(msg); |
| 365 | + } |
| 366 | + |
| 367 | + static async method(msg) { |
| 368 | + await this.someTask(msg); |
| 369 | + return msg; |
| 370 | + } |
| 371 | + } |
| 372 | + const msg = 'ok'; |
| 373 | + assert.strictEqual(await Runner.method(msg), msg); |
| 374 | + |
| 375 | + t.mock.method(Runner, Runner.someTask.name); |
| 376 | + assert.strictEqual(Runner.someTask.mock.calls.length, 0); |
| 377 | + |
| 378 | + assert.strictEqual(await Runner.method(msg), msg); |
| 379 | + |
| 380 | + const call = Runner.someTask.mock.calls[0]; |
| 381 | + |
| 382 | + assert.deepStrictEqual(call.arguments, [msg]); |
| 383 | + assert.strictEqual(await call.result, msg); |
| 384 | + assert.strictEqual(call.target, undefined); |
| 385 | + assert.strictEqual(call.this, Runner); |
| 386 | + |
| 387 | + assert.strictEqual(Runner.someTask.mock.restore(), undefined); |
| 388 | + assert.strictEqual(await Runner.method(msg), msg); |
| 389 | + assert.strictEqual(Runner.someTask.mock, undefined); |
| 390 | + assert.strictEqual(Runner.prototype.someTask, undefined); |
| 391 | + |
| 392 | +}); |
| 393 | + |
| 394 | +test('given null to a mock.method it throws a invalid argument error', (t) => { |
| 395 | + assert.throws(() => t.mock.method(null, {}), { code: 'ERR_INVALID_ARG_TYPE' }); |
| 396 | +}); |
| 397 | + |
| 398 | +test('it should throw given an inexistent property on a object instance', (t) => { |
| 399 | + assert.throws(() => t.mock.method({ abc: 0 }, 'non-existent'), { |
| 400 | + code: 'ERR_INVALID_ARG_VALUE' |
| 401 | + }); |
| 402 | +}); |
| 403 | + |
| 404 | +test('spy functions can be used on classes inheritance', (t) => { |
| 405 | + // Makes sure that having a null-prototype doesn't throw our system off |
| 406 | + class A extends null { |
| 407 | + static someTask(msg) { |
| 408 | + return msg; |
| 409 | + } |
| 410 | + static method(msg) { |
| 411 | + return this.someTask(msg); |
| 412 | + } |
| 413 | + } |
| 414 | + class B extends A {} |
| 415 | + class C extends B {} |
| 416 | + |
| 417 | + const msg = 'ok'; |
| 418 | + assert.strictEqual(C.method(msg), msg); |
| 419 | + |
| 420 | + t.mock.method(C, C.someTask.name); |
| 421 | + assert.strictEqual(C.someTask.mock.calls.length, 0); |
| 422 | + |
| 423 | + assert.strictEqual(C.method(msg), msg); |
| 424 | + |
| 425 | + const call = C.someTask.mock.calls[0]; |
| 426 | + |
| 427 | + assert.deepStrictEqual(call.arguments, [msg]); |
| 428 | + assert.strictEqual(call.result, msg); |
| 429 | + assert.strictEqual(call.target, undefined); |
| 430 | + assert.strictEqual(call.this, C); |
| 431 | + |
| 432 | + assert.strictEqual(C.someTask.mock.restore(), undefined); |
| 433 | + assert.strictEqual(C.method(msg), msg); |
| 434 | + assert.strictEqual(C.someTask.mock, undefined); |
| 435 | +}); |
| 436 | + |
| 437 | +test('spy functions don\'t affect the prototype chain', (t) => { |
| 438 | + |
| 439 | + class A { |
| 440 | + static someTask(msg) { |
| 441 | + return msg; |
| 442 | + } |
| 443 | + } |
| 444 | + class B extends A {} |
| 445 | + class C extends B {} |
| 446 | + |
| 447 | + const msg = 'ok'; |
| 448 | + |
| 449 | + const ABeforeMockIsUnchanged = Object.getOwnPropertyDescriptor(A, A.someTask.name); |
| 450 | + const BBeforeMockIsUnchanged = Object.getOwnPropertyDescriptor(B, B.someTask.name); |
| 451 | + const CBeforeMockShouldNotHaveDesc = Object.getOwnPropertyDescriptor(C, C.someTask.name); |
| 452 | + |
| 453 | + t.mock.method(C, C.someTask.name); |
| 454 | + C.someTask(msg); |
| 455 | + const BAfterMockIsUnchanged = Object.getOwnPropertyDescriptor(B, B.someTask.name); |
| 456 | + |
| 457 | + const AAfterMockIsUnchanged = Object.getOwnPropertyDescriptor(A, A.someTask.name); |
| 458 | + const CAfterMockHasDescriptor = Object.getOwnPropertyDescriptor(C, C.someTask.name); |
| 459 | + |
| 460 | + assert.strictEqual(CBeforeMockShouldNotHaveDesc, undefined); |
| 461 | + assert.ok(CAfterMockHasDescriptor); |
| 462 | + |
| 463 | + assert.deepStrictEqual(ABeforeMockIsUnchanged, AAfterMockIsUnchanged); |
| 464 | + assert.strictEqual(BBeforeMockIsUnchanged, BAfterMockIsUnchanged); |
| 465 | + assert.strictEqual(BBeforeMockIsUnchanged, undefined); |
| 466 | + |
| 467 | + assert.strictEqual(C.someTask.mock.restore(), undefined); |
| 468 | + const CAfterRestoreKeepsDescriptor = Object.getOwnPropertyDescriptor(C, C.someTask.name); |
| 469 | + assert.ok(CAfterRestoreKeepsDescriptor); |
| 470 | +}); |
| 471 | + |
322 | 472 | test('mocked functions report thrown errors', (t) => {
|
323 | 473 | const testError = new Error('test error');
|
324 | 474 | const fn = t.mock.fn(() => {
|
|
0 commit comments