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
Refactor test helpers #1336
Refactor test helpers #1336
Conversation
* Combine common codes from `parse` and `build`, and dispatch using `Mode` * Remove `toNotBuild` and `toNotParse` and use `expect.not` * Remove `Warning` and instead mock `console.warn` * Add `expect.toHavePassed` and check whether parse/build succeeded lazily * Improve failed test `message`: - Use color - Print stack traces(excluding internals) - Print diff - Follow jest matcher output style
Codecov Report
@@ Coverage Diff @@
## master #1336 +/- ##
=========================================
Coverage ? 83.87%
=========================================
Files ? 79
Lines ? 4539
Branches ? 797
=========================================
Hits ? 3807
Misses ? 639
Partials ? 93 Continue to review full report at Codecov.
|
The advantage of the previous global warning -> error conversion is that we could make sure no code produced warnings when it wasn't supposed to. In fact, I was going to suggest changing the default |
This comment has been minimized.
This comment has been minimized.
getParsed throws an error if parsing fails.
@ylemkimon are you planning changes or should I review? |
This comment has been minimized.
This comment has been minimized.
@ylemkimon I'm no longer in agreement on the warnings. Running from the command-line, I'd see warnings, but if they don't cause tests to fail, Travis will still allow the merge, which it shouldn't. Real-life example: In #1385 discussion, we spotted a bug through the existing warning -> error mechanism that we may not have noticed otherwise. |
@edemaine is there an action here for @ylemkimon? I'm not sure what the next step is for this PR. |
|
Since it sounds like there's still some changes pending I'm going to mark this as "needs-revision". |
…into jest-test-helpers
* Remove compareParseTree
This is ready for review. |
I'm going to try to look at this this weekend. I should've suggested saving the tagged template change for a separate PR. |
@kevinbarabash I agree. For review: |
const parseB = stripPositions(getParsed("x_3^2")); | ||
|
||
expect(parseA).toEqual(parseB); | ||
expect`x^2_3`.toParseLike`x_3^2`; |
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.
Changed to use toParseLike
. (b3dcf40)
expect("\text{hello% comment\n\nworld}") | ||
.toParseLike("\text{hello world}"); | ||
expect("\\text{hello% comment 1\nworld}").toParseLike`\text{helloworld}`; | ||
expect("\\text{hello% comment\n\nworld}").toParseLike`\text{hello world}`; |
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.
There were some cases of using single backslash with t
resulting in a horizontal tab(\t
). (17ca384)
@ylemkimon thanks for group the commits into logical groupings. I'll look at the individual commits when I do this review. |
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.
@ylemkimon thanks for taking a stab at this. It needs some discussion.
@@ -6,76 +6,76 @@ describe("Parser:", function() { | |||
|
|||
describe("#handleInfixNodes", function() { | |||
it("rejects repeated infix operators", function() { | |||
expect("1\\over 2\\over 3").toFailWithParseError( | |||
expect`1\over 2\over 3`.toFailWithParseError( |
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 looks a little strange to me b/c I'm not used to template strings returning things that aren't strings. Maybe we could introduce a tex
template literal function. It would look like:
expect(tex`1\over 2\over 3`).toFailWithParseError(...
The tex
function could be exported for use by other people. Also, it would be easier to understand what's going on. I'm still not sure how expect
is acting as a template function without us modifying/replacing it with our own implementation.
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.
@kevinbarabash I agree that it can be unfamiliar since it's new syntax. However, it's new way to call the function with arguments: an array of strings with raw
property, an array of raw strings, and expressions in ${}
. As expect
accepts any object, it just passes the first argument through and we can handle them in the matchers. Maybe we can document them in the CONTRIBUTING.md
?
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.
If expect
passes through only one argument, does that mean this won't work with ${interpolated expressions}
?
I don't think the new code looks much more confusing than the old code -- the weirdest part is that expect
just passes on its argument, and the action is in the chained methods afterward -- but that's a general Jest thing. However, until I read the template literal description I didn't really understand what the code was doing.
What about expectTex`1 \over 2 \over 3`
which is equivalent to expect(tex`1 \over 2 \over 3`)
, i.e., the string gets processed before calling expect
, instead of requiring all matches to process it? I think the weirdest part is overloading expect
in this unintended way (unless Jest suggests doing 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.
@edemaine Yes, it will throw an error if there are ${interpolated expressions}
and r
will return the part before the first one.
I think we can think of expect.toParse
as expect the raw string of the tagged literal to success parsing
.
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's not related, but Jest provides a way of creating a table using tagged template literal:
describe.each`
a | b | expected
${1} | ${1} | ${2}
${1} | ${2} | ${3}
${2} | ${1} | ${3}
`('$a + $b', ({a, b, expected}) => {
test(`returns ${expected}`, () => {
expect(a + b).toBe(expected);
});
test(`returned value not be greater than ${expected}`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(`returned value not be less than ${expected}`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});
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.
Interesting. I was unaware of jest's use of tagged template literals. expectTex
seems like a good compromise.
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.
@ylemkimon apologies for not raising my concerns about expect
as a tagged template earlier.
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.
@ylemkimon apologies for not raising my concerns about
expect
as a tagged template earlier.
I don't mind. I think productive discussion is necessary.
What about
expectTex`1 \over 2 \over 3`
which is equivalent toexpect(tex`1 \over 2 \over 3`)
, i.e., the string gets processed before callingexpect
, instead of requiring all matches to process it? I think the weirdest part is overloadingexpect
in this unintended way (unless Jest suggests doing this?).
Interesting. I was unaware of jest's use of tagged template literals.
expectTex
seems like a good compromise.
I still disagree. The purpose of using tagged template literal is to avoid using escape backslashes and simplify test cases. I think using expectTeX
defeats this purpose as there is no difference between processing before passing to expect
and processing in the matchers, when using KaTeX matchers.
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.
@ylemkimon There would be a difference if we needed to use Jest's matchers. But I can't actually think of any situation where we'd want to use those on a TeX string.
/** | ||
* Return the first raw string if x is tagged literal. Otherwise return x. | ||
*/ | ||
export const r = x => x != null && x.hasOwnProperty('raw') ? x.raw[0] : x; |
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 function needs a better name.
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.
@kevinbarabash I borrowed it from python's raw string prefix. Maybe tex
, as you suggested above?
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 wonder if people will want to use it like
tex`\frac{${num}}{${den}}`
That could be a separate PR though if people think that's worth supporting.
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.
@kevinbarabash Wouldn't it be same as String.raw
?
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 supposed it would be in which case I guess people can just use String.raw
. 😅
test/helpers.js
Outdated
try { | ||
return parseTree(expr, settings); | ||
expect(result).toHavePassed(); |
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 would expect getTree
to call katex.render()
and return the tree or clean up the stack trace and rethrow as necessary. Then expectKaTeX
can call getTree
and we don't have introduce a special matcher just to make things work in this order. Is there something I'm missing that necessitates this setup?
test/helpers.js
Outdated
}; | ||
|
||
export const buildAndSetResult = function(expr, result, | ||
settings = new Settings()) { | ||
export const expectKaTeX = (expr, settings = new Settings(), mode, isNot, |
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.
Does the default settings
work when undefined
is passed as the second arg?
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 really like that we're supporting .not
now, but this helper function has complicated the implementation quite a bit. I'd rather have a few small helper functions that each of the toParse()
, toBuild()
, etc. call then a single function that tries to do it all. Maybe we could add something format the message in addition to the function you added to clean up the stack trace.
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.
Does the default settings work when undefined is passed as the second arg?
Yes. Default function parameters allow formal parameters to be initialized with default values if no value or undefined
is passed.
* Move `_getBuilt` into `getBuilt` * Move default settings and tagging literal support in to `getParsed` and `getBuilt` * Remove stack traces clean-up * Remove `toHavePassed` matcher
Yes, I agree. My original intention was to reuse the error message from I've removed
With removing |
Sounds good. |
Done in fc47230. |
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.
Sorry for letting this sit for so long. Let's get this merged.
parse
andbuild
, and dispatch usingMode
toNotBuild
andtoNotParse
and useexpect.not
message
:(O = pass, X = fail)
* only if matches given string, if given
** only if doesn't match given string, if given