0

I am attempting to stub an instance method by following the top rated response in this topic: Jest: How to mock one specific method of a class

The method .getFileName() should normally take the 3rd argument and return the file name, in this case file.js. I thought I stubbed it to override and return scriptTag.js.

It still returns file.js meaning .mockImplementation() is not running during constructor().

Is there any way to override values assigned in the constructor with a spy or stubbing function? This would be helpful when instantiating inside a beforeEach, when I want to override the default constructor values.

ScriptTag.ts
  public localFileName: string;

  constructor(storeDomain: string, generalToken: string, filePath: string) {
    super(storeDomain, generalToken);
    this.localFileName = this.getFileName(this.filePath);
  }

  public getFileName(filePathOrUrl: string): string {
    const fileNameMatch: string[]|null = filePathOrUrl.match(/\/{1}(\w+.js)$/);
    if (Boolean(fileNameMatch)) { return fileNameMatch![1]; }
    else { throw Error("Filename not found"); }
  }
ScriptTag.test.ts
test("constructor()", () => {
  const scriptTag: ScriptTag = new ScriptTag("subdomain.shopify.com", 'generalTokenValue', "../path/to/file.js");
  const spy = jest
    .spyOn(scriptTag, "getFileName")
    .mockImplementation(() => "scriptTag.js");

  // expect(scriptTag.getFileName('x')).toEqual('scriptTag.js');
  expect(scriptTag.localFileName).toEqual('scriptTag.js');

});
terminal
  ✕ constructor() (10ms)

  ● constructor()

    expect(received).toEqual(expected) // deep equality

    Expected: "scriptTag.js"
    Received: "file.js"

      17 |   
      18 |   // expect(scriptTag.getFileName('x')).toEqual('scriptTag.js');
    > 19 |   expect(scriptTag.localFileName).toEqual('scriptTag.js');
         |                                   ^
      20 |   
      21 | });

      at Object.<anonymous> (functions/src/classes/__tests__/ScriptTag.test.ts:19:35)
Teneff
  • 30,564
  • 13
  • 72
  • 103
Sean D
  • 3,810
  • 11
  • 45
  • 90

1 Answers1

1

You instantiate the ScriptTag class, then the value of localFileName property is already assigned to file.js.

After instantiation, you use jest.spyOn to spy on the getFileName method. It's late.

You need spy on and make a stub for getFileName method before instantiating the ScriptTag class.

E.g.

ScriptTag.ts:

export class ScriptTag {
  localFileName = '';
  filePath = 'file.js';
  constructor(storeDomain: string, generalToken: string, filePath: string) {
    this.localFileName = this.getFileName(this.filePath);
  }

  public getFileName(filePathOrUrl: string): string {
    const fileNameMatch: string[] | null = filePathOrUrl.match(/\/{1}(\w+.js)$/);
    if (Boolean(fileNameMatch)) {
      return fileNameMatch![1];
    } else {
      throw Error('Filename not found');
    }
  }
}

ScriptTag.test.ts:

import { ScriptTag } from './ScriptTag';

describe('ScriptTag', () => {
  it('should pass', () => {
    jest.spyOn(ScriptTag.prototype, 'getFileName').mockImplementation(() => 'scriptTag.js');
    const scriptTag: ScriptTag = new ScriptTag('subdomain.shopify.com', 'generalTokenValue', '../path/to/file.js');
    expect(scriptTag.localFileName).toEqual('scriptTag.js');
    expect(scriptTag.getFileName).toBeCalled();
  });
});

Unit test result

 PASS  src/stackoverflow/59266532/ScriptTag.test.ts (10.73s)
  ScriptTag
    ✓ should pass (7ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        12.787s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59266532

Lin Du
  • 88,126
  • 95
  • 281
  • 483