-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Implement test suite runner #588
Conversation
I'll definitely try to take a look at this soon! Hopefully this weekend |
Wow, it took me so much time to understand the testing is supposed to be done with the command Regarding what I said earlier about the "only one test per file is not enough" stuff, I realised that multiple tests could actually be run simply by merging them into one...
so I guess this is not really an issue. |
Thanks for taking a look at it! 🎉
As you already mentioned you can just make the test case longer so that it tests multiple cases. We just need to find a balance between small and self-contained test cases and a myriad of too small test cases.
I also thought about the issue with broken syntax highlighting and have no real answer. Splitting the test and the expected result into two files is not a good idea so we won't find something that doesn't break syntax highlighting and in the same time works with a lot of different languages. So using a "neutral" file extension is probably the best way.
That is a good idea, I will add that. Another thought: should we also add the possibility to optionally add another section for a comment to a test case? Might be good for self-documenting the test case? Something like this:
(still open for suggestions about the test case file layout) |
I like the idea of the comment part. The test case file layout looks fine to me. It is both easy to create and easy to read. I kinda like the Phpt tests naming convention:
It could be simplified for Prism like this, for example:
BTW, is it possible to test language inclusion inside another? It requires both components to be loaded, even if they aren't dependent one from the other... Maybe the test case file could indicate another component is required? Also, do we need to write tests for known failures too? Those would be tests that we expect to fail, so that we will know if some change fixes them? (This sounds a bit weird...) |
## All test case files are now required to have the ".test" extension. This prevents issues with syntax highlighting in common IDEs and also prevents the test system to choke on non-testcase files in these directories (like `.DS_Store` or `Thumbs.db`). ## Hide the ".test" extension in the description of the test cases The message for a testcase `blabla.test` will now just read: > 1) Testing language 'css' – should pass test case 'blabla':
I just pushed comment support: I just use the I just pushed the requirement for all test cases to have the |
By using composed language names "language+language2+language3" you can test language inclusion or do integration tests.
I just pushed support for language inclusion / language integration tests By using composed language names like The first language ( |
If the implementation looks good, I will write some documentation. As soon as the docs are finished, this is ready for merging. |
Thanks for all those updates! This looks good to me. @LeaVerou, did you have time to take a look at this PR? What do you think of it? |
Thank you both! Looks good to me from a quick look. |
Great! :) Then, @apfelbox, tell us when the PR is ready for merging. |
@Golmote all right. I am currently moving (as in moving to another apartment) but may get some free time next week. |
var compiledTokenStream = Prism.tokenize(testCase.testSource, mainLanguageGrammar); | ||
var simplifiedTokenStream = this.transformCompiledTokenStream(compiledTokenStream); | ||
|
||
assert.deepEqual(simplifiedTokenStream, testCase.expectedTokenStream, testCase.comment); |
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.
@apfelbox: I think the two first parameters here should be swapped.
Currently, the "expected" and "actual" values look like they are inverted.
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.
See comment in your PR:
The docs say .deepEqual(actual, expected, [message])
, so the current implementation is correct.
@apfelbox: I ran into an issue related to language inclusion with the "lang1+lang2" feature. Actually, it seems that CSS and JS are the only exceptions here: they modify another grammar to add themselves into it. IMO, this is not the right way to do it. Currently, the CSS component adds itself inside Markup if it is available. I think it should be the opposite: Markup should add CSS inclusion if available, because it's much easier to know which languages can be embedded inside another, than to know which are the other languages a language can be embedded into. (I hope the previous sentence makes some sense...) What's your opinion on this, @LeaVerou? |
If we want to keep both ways of doing this, then we need a way to specify the main language to use in the test, that is not related to the order of the languages in the folder name. Maybe something like |
This might be an issue for patterns using the Consider the following test, that checks for strings in the
Because the
The first two are quite useless, don't you think? |
I think we should change that. We should unify the way languages extend each other.
No, the simplified token stream would look like this:
As the strings are not empty. My description is misleading.
“Strings” is meant here as generic character lists instead of the actual token
Then you would get
Does this clear things up? |
Are you sure about this? Because I don't reproduce this behaviour with your current code... With the following pattern in the grammar (here apacheconf): 'string': {
pattern: /("|').*\1/,
inside: {
'variable': /(\$|%)\{?(\w\.?(\+|\-|:)?)+\}?/
}
}, and the following test:
Here is the result I get:
|
@LeaVerou Would you be okay with this? (moving CSS inclusion and JS inclusion into the Markup component) |
We could include them. But I would remove all strings, that just include whitespace, like |
Sounds good to me. Just make sure to do this at each level of recursion. |
Pull the token stream transformation out of the test case into its own component.
It now strips empty values
We are at a point where we probably should test the test runner (especially the token stream transformer) itself.
I just pushed some updates. I think I got it all – I even managed to reduce code complexity a bit. If you want to learn the details about the token stream transformation you can check the newly created test file |
…except type and content
I think you forgot the filter the blank strings (that just contain whitespaces) you were talking about. [EDIT: Oh, sorry, you actually did filter them. I got confused again with those colors and the meaning of actual and expected in the diff...] Also, since we don't hear from @LeaVerou regarding the BC breaking change for language inclusions, would you mind allowing both behaviours for now? i.e. we need to assume the main language is the last one listed, because this is the most common case, and we need a way to override this behaviour for the CSS and JS components (I suggested tagging the main language with some character like "!" but any solution would do). |
Also, I think your example |
Oh, and one last thing, since you commited about quote style consistency, I noticed you are not consistent in the position of the curly braces (sometimes at the end of the line, sometimes on their own line)? ^^ Prism mostly uses braces at the end of the line. |
You can add an exclamation mark anywhere in the name to load it as main language. If you do not specify anything, the first entry is used as main language css+markup! --> markup is main language css+markup --> css is main language
@Golmote sorry for the delay. All done. |
Just added travis support. You can see the result of the travis build of my fork here: https://travis-ci.org/apfelbox/prism |
And I finally pushed a documentation page, explaining the test runner, test suite and everything in it (I am no native speaker, so please correct me if anything doesn't make sense 😉 ). |
This is now ready to be merged |
A final note:
What do you think? |
It might be useful indeed, but maybe we can wait for an actual use case. ^^ I'll merge the PR during next week, as I'm still away from home right now. I already wrote a bunch of tests for a few components, so I will also submit PRs for them. |
Here we go! :) |
🎉 thanks |
I finally got around on implementing a simple (?) test suite runner. For now, the test suite runs in node, so just the language definitions will be tested, not the integration with the browser. We won't catch things like unsupported methods in old browser for now. (So, if your language definition uses
[].forEach
the test suite will pass (as node supports this), but IEold will fail as the method is unsupported there.)Test case location
All tests are located in
/tests/languages/${language}/${file}
.${language}
must match the name of the language definition incomponents.js
.${file}
is just a file name and only used to provide an info to the test runner.So if the directory looks like this:
your output will look like this:
As you can see the file name doesn't matter, it is only included in the test description (that you can quickly find your failing tests).
Test case specification
Please provide feedback / better ideas than mine here.
An example test case file looks like this:
It consists of
Please consider that the test case specification does use some simplifications / expectations. I tried to find a well enough mix of "too much magic" and "way too much to write and manage". Please be lenient with me here.
Prism.tokenize()
), but it is an array of two-element arrays. The only reason to do this is to reduce the amount of text you need to write for a test case.token.type
andtoken.content
are compared, something liketoken.alias
is just ignored.[${type}, ${content}]
Implemention
The implemention looks like this:
As the language definitions (and Prism itself) doesn't use proper encapsulation (Prism is a global singleton), some hoop-jumping is required for this work: we need to run the source code in a vm in node (natively supported in
require("vm")
, docs) and pass the context manually in their. This way we can build completely fresh and isolated Prism instances for each test (so that they won't interfere with each other).This kills performance but as we can't just use
new Prism()
, this is required for ensuring that the tests run in isolation (even different tests in the same language should ideally use different instances – as they currently do).This is not exactly ideal for performance... but let's write tests and worry about testing performance later! 🎉
ToDo
Intended to replace/refresh #355