-
-
Notifications
You must be signed in to change notification settings - Fork 503
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
Conversation
balavishnuvj
commented
Oct 13, 2020
•
edited by kettanaito
Loading
edited by kettanaito
- Closes Predicate for Logs #420
There was a problem hiding this 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 :)
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() | ||
}) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()
})
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
src/setupWorker/glossary.ts
Outdated
quiet?: boolean | ||
quiet?: | ||
| boolean | ||
| ((req?: MockedRequest, res?: ResponseWithSerializedHeaders) => boolean) |
There was a problem hiding this comment.
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 ?
.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) => { |
There was a problem hiding this comment.
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.
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() | ||
}) |
There was a problem hiding this comment.
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 @marcosvega91 please do let me know your concerns are not addressed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM :) thanks :)
3e8a8c1
to
c12dea9
Compare
@kettanaito what needs to be done here? bit confused 😅 |
looks like a simpler |
@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. |
@lukesmurray, hey 👋 You're right, you can already silence the logging by passing |
548fbd0
to
fed3b21
Compare
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. |