Skip to content
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

Adds DevMock Service #7

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open

Adds DevMock Service #7

wants to merge 8 commits into from

Conversation

Krakabek
Copy link
Collaborator

Description:

Dev Mock Service Worker is an API mocking library that allows you to specify custom responses for any API calls inside your app.

🧪 Testing Steps / Validation

  • Unit tests
  • NPM link on a real app to verify the mocked request works

✅ Checks

  • Contributor License Agreement (CLA) completed if not a Reddit employee

Copy link
Member

@niedzielski niedzielski left a comment

Choose a reason for hiding this comment

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

looks like it could be very useful! only concerns are: bundle size and confusion over all the "devv" and "dev" terminology which seems like it's just mocking.

src/dev-mock-service/redis-mock-service/types.ts Outdated Show resolved Hide resolved
src/dev-mock-service/redis-mock-service/index.ts Outdated Show resolved Hide resolved
} from "./types.js";
import type { HandlerOverride } from "../types/internal.js";

export const createDevvRedis = (
Copy link
Member

Choose a reason for hiding this comment

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

suggest calling this createDevvitRedis(). I don't think we use Devv anywhere in any of the codebases (rg -w Devv comes up empty in shreddit and devvit repos). would love to not have a new term to grep. that said, I think everything here is pretty devvit-y so also consider newMockRedis(). same request for createDevvRedditApi(), DevvRedditApi, and everywhere else.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am not sure about the naming here, because it's not a mockRedis, it's an instance that intercepts some redis requests, but fires real ones for the rest
So calling it mockRedis might lead to an expectation that it only performs mock requests

Devv was a way to do the reference to devvit and developer at the same time, and I did not come up with a better option yet

src/dev-mock-service/redis-mock-service/index.test.ts Outdated Show resolved Hide resolved
src/dev-mock-service/reddit-api-mock-service/index.ts Outdated Show resolved Hide resolved
@@ -0,0 +1,47 @@
## Dev Mock Service
Copy link
Member

Choose a reason for hiding this comment

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

🔕 suggest consider renaming to just "mocks". "dev" and "service" aren't buying me much. same thing with the subdirectory names which could be like mock-reddit instead of reddit-api-mock-service.

Redis, RedditAPI, or HTTP request.

- In Dev mode (`DevMockMode.Dev`), handlers are applied for all requests with the matching method and ID (if available).
- In Prod mode (`DevMockMode.Prod`), handlers are ignored.
Copy link
Member

Choose a reason for hiding this comment

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

this will encourage users to ship development-only code which may be large. I'd love to see this code fall out of apps for at least non-prerelease builds so there wasn't a wrong way to use it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

How can I achieve this?

Copy link

Choose a reason for hiding this comment

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

I'd like the introduction of a IS_PROD or NODE_ENV or IS_PLAYTEST environmental variable that could be statically added at build time for tree shaking. Would be useful for more than just here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I wonder if we can implement the IS_PLAYTEST and tree shaking separately, so it does not block this PR

Comment on lines 28 to 30
devvRedis: RedisClient;
devvRedditApi: RedditAPIClient;
devvFetch: typeof fetch;
Copy link
Member

Choose a reason for hiding this comment

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

suggest omitting the name devv prefix names (I make a comment about this later that it's a new term) because I don't think it's adding much useful context here. the user only needs to know which service is which and the typing covers that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is done to avoid confusion with the actual instances of redis and reddit
Imagine the following scenario

const {redis, reddit} = context;
const { devvRedis, devvRedditApi, devvFetch } = DevMock.createService({...

Without the prefix there is a potential name collision

src/dev-mock-service/http-mock-service/index.ts Outdated Show resolved Hide resolved
@@ -0,0 +1,6 @@
export type HttpOverride = {
Copy link
Member

Choose a reason for hiding this comment

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

I think users end up interacting with this type a bit? if so, consider documenting in JSDocs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a purely internal type, used to filter overrides based on the type

Copy link

@mwood23 mwood23 left a comment

Choose a reason for hiding this comment

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

I really appreciate you taking the time to mock all of these services out! I think I need an example to understand it more. It looks like a design goal here was to avoid any alterations to public-api or the underlying build system which I understand. I do wish this is something we could do without touching the app code.

Some areas I'd consider exploring:

  • Everything is mocked by default and a helpful error is throw if a network request is triggered. I think this is a sound default since an app only has one redis. Running the tests and triggering a bunch of writes to the DB would be bad vibes.
  • Is there a way to alter the implementation details of these functions under the hood to make it transparent to the caller. For example, when running the tests, what if we found a way to mutate the context singleton automatically instead of putting a function in front of them.

This triggers some folks (and I totally understand), but I'm a fan of writing my own test harness that wrap describe and it. Then you have take care of isolating stuff in true integration tests (aka creating a new userId per test so you can parallelize them). Or, in this case, automatically restore all of the mocks. Something like this:

import { DevvitTestHarness } from 'somewhere'

DevvitTestHarness.it('should do xyz', [
DevMock.fetch.get("https://example.com", () =>
      DevMock.httpResponse.ok({ fetched: "mock" }),
    )
], () => {
expect('https://example.com').toBe('mock')
})

@@ -0,0 +1,47 @@
## Dev Mock Service

Dev Mock Service Worker is an API mocking library that allows you to specify
Copy link

Choose a reason for hiding this comment

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

This isn't actually a server worker is it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Whoops, bad copy paste 😅

Redis, RedditAPI, or HTTP request.

- In Dev mode (`DevMockMode.Dev`), handlers are applied for all requests with the matching method and ID (if available).
- In Prod mode (`DevMockMode.Prod`), handlers are ignored.
Copy link

Choose a reason for hiding this comment

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

I'd like the introduction of a IS_PROD or NODE_ENV or IS_PLAYTEST environmental variable that could be statically added at build time for tree shaking. Would be useful for more than just here

import type { HandlerOverride } from "../types/index.js";
import type { ModMailService } from "@devvit/public-api";

class DevvRedditApi implements RedditApiInterface {
Copy link

Choose a reason for hiding this comment

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

Thanks for all of the leg work here!


```typescript
const redisValue = await devvRedis.get("mocked_key"); // "Value from mocks!"
const fetchedValue = await(await devvFetch("https://example.com")).json(); // {fetched: "mock"}
Copy link

Choose a reason for hiding this comment

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

nit: double await sort of always been a weird pattern to me instead of an intermediate var. Especially to noobies

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is just an example to demonstrate the responses
Do you think it's worth breaking into 3 sections? redis, reddit and fetch separately


#### Setup

Create devv versions of the API clients you want to mock.
Copy link

Choose a reason for hiding this comment

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

Is this in the test file or in the real app code?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Real app code, this molecule is not intended to be used in unit tests (however it certainly can be)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants