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

feat: supports custom predicate as the "quiet" option value #424

Closed
wants to merge 4 commits into from

Conversation

balavishnuvj
Copy link
Contributor

@balavishnuvj balavishnuvj commented Oct 13, 2020

Copy link
Member

@marcosvega91 marcosvega91 left a comment

Choose a reason for hiding this comment

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

Hey @balavishnuvj thanks for working on this great feature ! :)

I have a suggestion about the project structure. Let me know that you think :)

Comment on lines 1 to 84
import * as path from 'path'
import { TestAPI, runBrowserWith } from '../../../support/runBrowserWith'
import { captureConsole } from '../../../support/captureConsole'

let runtime: TestAPI

beforeAll(async () => {
runtime = await runBrowserWith(
path.resolve(__dirname, 'quiet.fn.true.mocks.ts'),
)
})

afterAll(() => {
return runtime.cleanup()
})

test('log the captured request when the "quiet" option is returns to "false"', async () => {
const { messages } = captureConsole(runtime.page)

await runtime.page.evaluate(() => {
// @ts-ignore
return window.__MSW_REGISTRATION__
})

await runtime.reload()

const activationMessage = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW] Mocking enabled.')
})
expect(activationMessage).toBeFalsy()

const res = await runtime.request({
url: `${runtime.origin}/user`,
})

const headers = res.headers()
const body = await res.json()

expect(headers).toHaveProperty('x-powered-by', 'msw')
expect(body).toEqual({
firstName: 'John',
age: 32,
})

const requetsLog = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW]') && text.includes('GET /user')
})
expect(requetsLog).toBeTruthy()
})

test('does not log the captured request when the "quiet" option is returns to "true"', async () => {
const { messages } = captureConsole(runtime.page)

await runtime.page.evaluate(() => {
// @ts-ignore
return window.__MSW_REGISTRATION__
})

await runtime.reload()

const activationMessage = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW] Mocking enabled.')
})
expect(activationMessage).toBeFalsy()

const res = await runtime.request({
url: `${runtime.origin}/foo`,
})

const headers = res.headers()
const body = await res.json()

expect(headers).toHaveProperty('x-powered-by', 'msw')
expect(body).toEqual({
firstName: 'John',
age: 32,
})

const requetsLog = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW]') && text.includes('GET /foo')
})

expect(requetsLog).toBeUndefined()
})
Copy link
Member

@marcosvega91 marcosvega91 Oct 13, 2020

Choose a reason for hiding this comment

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

I think that we can integrate this test in quiet.test.ts.

we can update the quiet.mock.ts as

import { setupWorker, rest } from 'msw'

const worker = setupWorker(
  rest.get('/user', (req, res, ctx) => {
    return res(
      ctx.json({
        firstName: 'John',
        age: 32,
      }),
    )
  }),
  rest.get('/foo', (req, res, ctx) => {
    return res(
      ctx.json({
        firstName: 'John',
        age: 32,
      }),
    )
  }),
)

// @ts-ignore
window.__MSW_START__ = worker.start

the in the quiet.test.ts we can do as

+  await runtime.reload()
+
   await runtime.page.evaluate(() => {
     // @ts-ignore
-    return window.__MSW_REGISTRATION__
+    return window.__MSW_START__({
+      // Disable logging of matched requests into browser's console
+      quiet: function (req) {
+        if (req) {
+          return req.url.href.includes('foo')
+        }
+        return true
+      },
+    })
   })
 
-  await runtime.reload()

In this way we can call the function __MSW_START__ with the right options. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah this looks great, will update. What does await runtime.reload() do? Do I have to remove it?

Copy link
Member

Choose a reason for hiding this comment

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

it will reload the page, because we have a single instance of puppeteer it is necessary to have everything clean between test. It should be called before the evaluate.

So when the test runs it will reload the page and then start MSW.

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 that we can add in a beforeEach instead

beforeEach(() => {
  await runtime.reload()
})

Copy link
Member

Choose a reason for hiding this comment

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

We can also introduce a different test suite like quiet-predicate to scope the predicate functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

both works for me, I created new file because I thought that was convention that being followed.
eg. wait-until-ready.false.mocks.ts and wait-until-ready.error.mocks.ts
let me know which works better?

quiet?: boolean
quiet?:
| boolean
| ((req?: MockedRequest, res?: ResponseWithSerializedHeaders) => boolean)
Copy link
Member

Choose a reason for hiding this comment

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

By the time we analyze the quiet option and output a successful mock to console both req and res exist. No need to annotate them as optional with ?.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this was to handle src/setupWorker/start/utils/activateMocking.ts, there quiet can be a function without and req and res. Or am I missing anything?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I understand the intention. As I've stated earlier, such internal events like ACTIVATE_MOCKING shouldn't be controlled by the predicate function of the quiet option.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we remove the quiet check from this log altogether?

Copy link
Member

Choose a reason for hiding this comment

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

That's a sensible approach, yet it would be a breaking change then. Previously this log was also controlled by options.quiet.

Alternatively, maybe we should distribute a function-as-value in a different option?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, it makes sense to introduce different option to handle this case.
but then usage seems a bit tricky,

{
quiet: true,
quietPredicate: (req) => {
      return req.url.href.includes('profile')
  },
}

what is expected might be a not sure.

we could ntroducte another option for internal logs

quiet:  (req) => {
      return req.url.href.includes('profile')
  },
quietInternals: true

we can come up with better names for sure 😅

@@ -7,7 +7,9 @@ export const activateMocking = async (
context.worker?.postMessage('MOCK_ACTIVATE')

return context.events.once('MOCKING_ENABLED').then(() => {
if (!options?.quiet) {
const isQuiet =
typeof options?.quiet === 'function' ? options?.quiet() : options?.quiet
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should execute a quiet predicate function here. How about we only check the options.quiet for truthiness?

// Basically, keeping the previous implementation.
if (!options?.quiet)

This is an internal log message not bound to any request. It should still abide by quiet: true in case you want to silence all logs, but it shouldn't support predicate as there is no request context to execute the predicate in.

What are your thoughts on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

wouldn't the options?.quiet be a function?

Copy link
Member

Choose a reason for hiding this comment

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

A good point, as a function value produces a truthy value, while the option describes a negative value (true for disable).

Copy link
Member

Choose a reason for hiding this comment

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

This raises an entirely new concern: how can one have a custom logging predicate for requests and also disable the internal messages? The current quiet option value cannot handle this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

either we make req and res in callback optional or introduce a new option

}),
)
}),
rest.get('/foo', (req, res, ctx) => {
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest to use realistic paths so that these usage examples resemble actual usage.

Comment on lines 1 to 84
import * as path from 'path'
import { TestAPI, runBrowserWith } from '../../../support/runBrowserWith'
import { captureConsole } from '../../../support/captureConsole'

let runtime: TestAPI

beforeAll(async () => {
runtime = await runBrowserWith(
path.resolve(__dirname, 'quiet.fn.true.mocks.ts'),
)
})

afterAll(() => {
return runtime.cleanup()
})

test('log the captured request when the "quiet" option is returns to "false"', async () => {
const { messages } = captureConsole(runtime.page)

await runtime.page.evaluate(() => {
// @ts-ignore
return window.__MSW_REGISTRATION__
})

await runtime.reload()

const activationMessage = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW] Mocking enabled.')
})
expect(activationMessage).toBeFalsy()

const res = await runtime.request({
url: `${runtime.origin}/user`,
})

const headers = res.headers()
const body = await res.json()

expect(headers).toHaveProperty('x-powered-by', 'msw')
expect(body).toEqual({
firstName: 'John',
age: 32,
})

const requetsLog = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW]') && text.includes('GET /user')
})
expect(requetsLog).toBeTruthy()
})

test('does not log the captured request when the "quiet" option is returns to "true"', async () => {
const { messages } = captureConsole(runtime.page)

await runtime.page.evaluate(() => {
// @ts-ignore
return window.__MSW_REGISTRATION__
})

await runtime.reload()

const activationMessage = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW] Mocking enabled.')
})
expect(activationMessage).toBeFalsy()

const res = await runtime.request({
url: `${runtime.origin}/foo`,
})

const headers = res.headers()
const body = await res.json()

expect(headers).toHaveProperty('x-powered-by', 'msw')
expect(body).toEqual({
firstName: 'John',
age: 32,
})

const requetsLog = messages.startGroupCollapsed.find((text) => {
return text.includes('[MSW]') && text.includes('GET /foo')
})

expect(requetsLog).toBeUndefined()
})
Copy link
Member

Choose a reason for hiding this comment

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

We can also introduce a different test suite like quiet-predicate to scope the predicate functionality.

@kettanaito kettanaito changed the title feat: add qiet as predicate function feat: supports custom predicate as the "quiet" option value Oct 14, 2020
@balavishnuvj
Copy link
Contributor Author

@kettanaito @marcosvega91 please do let me know your concerns are not addressed.

marcosvega91
marcosvega91 previously approved these changes Oct 15, 2020
Copy link
Member

@marcosvega91 marcosvega91 left a comment

Choose a reason for hiding this comment

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

LGTM :) thanks :)

@balavishnuvj
Copy link
Contributor Author

@kettanaito what needs to be done here? bit confused 😅

@lukesmurray
Copy link

looks like a simpler quiet: boolean was merged here. Not sure what the status of this is.

@kettanaito
Copy link
Member

@balavishnuvj, sorry, I've lost the context of these changes after a while. Worry not, I will check what's left to do, if anything, and update the review status. The issues/active collaborators ratio is rather high, so certain features although useful and awesome don't get as much attention as they deserve.

@kettanaito
Copy link
Member

@lukesmurray, hey 👋 You're right, you can already silence the logging by passing quiet: false to either worker.start() or server.listen(). This pull request aims for that quiet option to support a custom predicate, so you may choose which requests to log and which to ignore.

@kettanaito
Copy link
Member

Thanks once again for working on this, @balavishnuvj!

I think I will close this one. I can see this being a useful feature but it has a few cost points that don't quite justify the gain here. It's an additional config, and I'd like to be extremely strict when it comes to it. Moreover, this hasn't been requested as a missing feature for three years the pull request has been open.

I'd be glad to circle back on this if more people find this missing. Until then, closing.

@kettanaito kettanaito closed this Mar 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Predicate for Logs
4 participants