Search code examples
typescriptjestjsts-jest

How to reuse a jest test for multiple impementations of the same interface?


I have a test:

describe("Given a config repository", () => {
    let target: ConfigRepository;

    beforeEach(() => {
        target = InMemoryConfigRepository();
    });

    test("When creating a new config, Then it is persisted properly", async () => {
        const key = "key";
        const namespace = "namespace";
        const result = await target.upsert({
            key,
            namespace,
            value: "value",
            teamId: "teamId",
        })();
        const configs = await target.findAll()();

        expect(result._tag).toEqual("Right");
        expect(configs.length).toBe(1);
        expect(configs.map((c) => c.key)).toEqual([key]);
    });
});

that can be applied against an implementation of my interface:

export type ConfigRepository = {
    get: <T extends RequiredJsonObject>(
        props: ConfigurationProperties<T>
    ) => TE.TaskEither<DatabaseError | MissingConfigError, ConfigEntity[]>;
    findAll(): T.Task<ConfigEntity[]>;
    upsert: (
        config: UnsavedConfig
    ) => TE.TaskEither<DatabaseError, ConfigEntity>;
};

My problem is that I don't see a clear way of applying this to different implementations of the same interface. How can I test say a PrismaConfigRepository with the same test?


Solution

  • You probably want to to whats called a Parameterized Test. One way to implement this is to use .each. The idea is then to pass the constructor of each of your classes implementing the ConfigRepository interface as a parameter, and constructing the instances using the constructor in beforeEach (rather than always instanciating an InMemoryConfigRepository).

    Rough sketch of what this could look like:

    describe.each(
       [[InMemoryConfigRepository],[PrismaConfigRepository]]
    )(
       "Given a config repository (implementation no. %#)", 
       (configRepositoryConstructor: new () => ConfigRepository) => {
            let target: ConfigRepository;
    
            beforeEach(() => {
                target = configRepositoryConstructor();
            });
    
            test("When creating a new config, Then it is persisted properly", async () => {
               // current test implementation
            });
       }
    );