Skip to content

test(idempotency): simplify wrapper & middleware tests #2919

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 13, 2024

Conversation

dreamorosi
Copy link
Contributor

Summary

Changes

Please provide a summary of what's being changed

This PR consolidates the unit tests for the makeIdempotent function wrapper and the makeHandlerIdempotent Middy.js middleware, thus reducing duplication and maintenance overhead.

More than 90% of the test cases and assertions within the tests of the two files were the exact same, resulting in a code duplication of almost 70%. This PR consolidates the tests in a single file using the the it.each() feature present in Jest.

For example, instead of having two test cases that only differ in how the handler is wrapped, we now have cases like this:

it.each([
  {
    type: 'wrapper',
  },
  { type: 'middleware' },
])(
  'does not do anything if idempotency is disabled ($type)',
  async ({ type }) => {
    // Prepare
    process.env.POWERTOOLS_IDEMPOTENCY_DISABLED = 'true';
    const handler =
      type === 'wrapper'
        ? makeIdempotent(fnSuccessfull, mockIdempotencyOptions)
        : middy(fnSuccessfull).use(
            makeHandlerIdempotent(mockIdempotencyOptions)
          );
    const saveInProgressSpy = jest.spyOn(
      mockIdempotencyOptions.persistenceStore,
      'saveInProgress'
    );
    const saveSuccessSpy = jest.spyOn(
      mockIdempotencyOptions.persistenceStore,
      'saveSuccess'
    );

    // Act
    const result = await handler(event, context);

    // Assess
    expect(result).toBe(true);
    expect(saveInProgressSpy).toHaveBeenCalledTimes(0);
    expect(saveSuccessSpy).toHaveBeenCalledTimes(0);
  }
);

In short, we now run two test cases with a discriminator (type) which instantiates the handler constant either using the function wrapper or Middy.js middleware, then carry on with the tests as normal.

The resulting test file has most of the test cases setup as described above, and only a handful of cases (<5) that are specific to one or the other method.

The logs/outputs of the tests are still distinguishable thanks to the templating used in the test case description:

Function: makeIdempotent
    ✓ handles a successful execution (wrapper) (3 ms)
    ✓ handles a successful execution (middleware) (8 ms)
    ✓ handles an execution that throws an error (wrapper) (9 ms)
    ✓ handles an execution that throws an error (middleware) (3 ms)
    ✓ thows an error if the persistence layer throws an error when saving in progress (wrapper) (1 ms)
    ✓ thows an error if the persistence layer throws an error when saving in progress (middleware) (1 ms)

Please add the issue number below, if no issue is present the PR might get blocked and not be reviewed

Issue number: closes #2918


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@dreamorosi dreamorosi self-assigned this Aug 13, 2024
@dreamorosi dreamorosi requested a review from a team August 13, 2024 11:37
@dreamorosi dreamorosi requested a review from a team as a code owner August 13, 2024 11:37
@boring-cyborg boring-cyborg bot added the tests PRs that add or change tests label Aug 13, 2024
@pull-request-size pull-request-size bot added the size/XL PRs between 500-999 LOC, often PRs that grown with feedback label Aug 13, 2024
Copy link

sonarqubecloud bot commented Aug 13, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
27.5% Duplication on New Code

See analysis details on SonarCloud

@dreamorosi dreamorosi requested a review from am29d August 13, 2024 13:17
Copy link
Contributor

@am29d am29d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactoring! Sonar still complains of code duplication and I assume this needs to be executed in the test scope or can we extract it to one function in the describe block?

      type === 'wrapper'
         ? makeIdempotent(fn, mockIdempotencyOptions)
         : middy(fn).use(makeHandlerIdempotent(mockIdempotencyOptions));
         ```

@dreamorosi
Copy link
Contributor Author

dreamorosi commented Aug 13, 2024

Nice refactoring! Sonar still complains of code duplication and I assume this needs to be executed in the test scope or can we extract it to one function in the describe block?

      type === 'wrapper'
         ? makeIdempotent(fn, mockIdempotencyOptions)
         : middy(fn).use(makeHandlerIdempotent(mockIdempotencyOptions));
         ```

Thanks!

Many/most of them have different fn or different options albeit with some patterns, that's why it's run there.

We could probably create a function factory and shave off a few more lines, but that would probably require a bit more attention, mainly to avoid to hide completely the test case from the reader.

It's an area that I'd like to explore further, but for today I think we could take the win of going from ~70% to 20% duplication.

@am29d am29d merged commit 9e5fa64 into main Aug 13, 2024
15 checks passed
@am29d am29d deleted the test/idempotency_test_simplify branch August 13, 2024 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/XL PRs between 500-999 LOC, often PRs that grown with feedback tests PRs that add or change tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Maintenance: remove duplication in Idempotency tests
2 participants