cssSelectorSpecs.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. var vows = require('vows'),
  2. assert = require('assert'),
  3. selectorGrammar = require(__dirname + '/grammarInvoker');
  4. var shouldParse = function() {
  5. var selector,
  6. context = {
  7. topic: function() {
  8. selector = this.context.name;
  9. selectorGrammar.parse(selector, this.callback);
  10. }
  11. };
  12. context['should parse selector'] = function(err, parsedSelector) {
  13. if(err) {
  14. assert.fail(err.inner.toString());
  15. } else {
  16. assert.equal(parsedSelector, selector);
  17. }
  18. };
  19. return context;
  20. };
  21. var shouldParseTo = function(expectedSelector) {
  22. var context = {
  23. topic: function() {
  24. var selector = this.context.name;
  25. selectorGrammar.parse(selector, this.callback);
  26. }
  27. };
  28. context['should parse selector'] = function(err, parsedSelector) {
  29. if(err) {
  30. assert.fail(err.inner.toString());
  31. } else {
  32. assert.equal(parsedSelector, expectedSelector);
  33. }
  34. };
  35. return context;
  36. };
  37. vows.describe('Summarized Selectors').addBatch({
  38. // Taken from http://www.w3.org/TR/css3-selectors/#selectors
  39. '*': shouldParse(),
  40. 'E': shouldParse(),
  41. 'E[foo]': shouldParse(),
  42. 'E[foo="bar"]': shouldParse(),
  43. 'E[foo~="bar"]': shouldParse(),
  44. 'E[foo^="bar"]': shouldParse(),
  45. 'E[foo$="bar"]': shouldParse(),
  46. 'E[foo*="bar"]': shouldParse(),
  47. 'E[foo|="en"]': shouldParse(),
  48. 'E:root': shouldParse(),
  49. 'E:nth-child(n)': shouldParse(),
  50. 'E:nth-last-child(n)': shouldParse(),
  51. 'E:nth-of-type(n)': shouldParse(),
  52. 'E:nth-last-of-type(n)': shouldParse(),
  53. 'E:first-child': shouldParse(),
  54. 'E:last-child': shouldParse(),
  55. 'E:first-of-type': shouldParse(),
  56. 'E:last-of-type': shouldParse(),
  57. 'E:only-child': shouldParse(),
  58. 'E:only-of-type': shouldParse(),
  59. 'E:empty': shouldParse(),
  60. 'E:link': shouldParse(),
  61. 'E:visited': shouldParse(),
  62. 'E:active': shouldParse(),
  63. 'E:hover': shouldParse(),
  64. 'E:focus': shouldParse(),
  65. 'E:target': shouldParse(),
  66. 'E:lang(fr)': shouldParse(),
  67. 'E:enabled': shouldParse(),
  68. 'E:disabled': shouldParse(),
  69. 'E:checked': shouldParse(),
  70. 'E::first-line': shouldParse(),
  71. 'E::first-letter': shouldParse(),
  72. 'E::before': shouldParse(),
  73. 'E::after': shouldParse(),
  74. 'E.warning': shouldParse(),
  75. 'E#myid': shouldParse(),
  76. 'E:not(s)': shouldParse(),
  77. 'E F': shouldParse(),
  78. 'E > F': shouldParse(),
  79. 'E + F': shouldParse(),
  80. 'E ~ F': shouldParse()
  81. }).run();
  82. vows.describe('Lonely Selectors').addBatch({
  83. // Taken from http://www.w3.org/TR/css3-selectors/#selectors,
  84. // but without the element names
  85. '[foo]': shouldParse(),
  86. '[foo="bar"]': shouldParse(),
  87. '[foo~="bar"]': shouldParse(),
  88. '[foo^="bar"]': shouldParse(),
  89. '[foo$="bar"]': shouldParse(),
  90. '[foo*="bar"]': shouldParse(),
  91. '[foo|="en"]': shouldParse(),
  92. ':root': shouldParse(),
  93. ':nth-child(n)': shouldParse(),
  94. ':nth-last-child(n)': shouldParse(),
  95. ':nth-of-type(n)': shouldParse(),
  96. ':nth-last-of-type(n)': shouldParse(),
  97. ':first-child': shouldParse(),
  98. ':last-child': shouldParse(),
  99. ':first-of-type': shouldParse(),
  100. ':last-of-type': shouldParse(),
  101. ':only-child': shouldParse(),
  102. ':only-of-type': shouldParse(),
  103. ':empty': shouldParse(),
  104. ':link': shouldParse(),
  105. ':visited': shouldParse(),
  106. ':active': shouldParse(),
  107. ':hover': shouldParse(),
  108. ':focus': shouldParse(),
  109. ':target': shouldParse(),
  110. ':lang(fr)': shouldParse(),
  111. ':enabled': shouldParse(),
  112. ':disabled': shouldParse(),
  113. ':checked': shouldParse(),
  114. '::first-line': shouldParse(),
  115. '::first-letter': shouldParse(),
  116. '::before': shouldParse(),
  117. '::after': shouldParse(),
  118. '.warning': shouldParse(),
  119. '#myid': shouldParse(),
  120. ':not(s)': shouldParse()
  121. }).run();
  122. vows.describe('Attribute Selectors with Identifiers').addBatch({
  123. '[foo~=bar]': shouldParse(),
  124. '[foo^=bar]': shouldParse(),
  125. '[foo$=bar]': shouldParse(),
  126. '[foo*=bar]': shouldParse(),
  127. '[foo|=en]': shouldParse()
  128. }).run();
  129. vows.describe('Nth Selectors').addBatch({
  130. ':nth-child(-n)': shouldParse(),
  131. ':nth-child(+n)': shouldParse(),
  132. ':nth-child(even)': shouldParse(),
  133. ':nth-child(odd)': shouldParse(),
  134. ':nth-child(50)': shouldParse(),
  135. ':nth-child(-50)': shouldParse(),
  136. ':nth-child(+50)': shouldParse(),
  137. ':nth-child(2n+3)': shouldParse(),
  138. ':nth-child(2n-3)': shouldParse(),
  139. ':nth-child(+2n-3)': shouldParse(),
  140. ':nth-child(-2n+3)': shouldParse(),
  141. ':nth-child(-2n+ 3)': shouldParse(),
  142. ':nth-child(-2n+ 3)': shouldParse(),
  143. ':nth-child(-2n+ 3)': shouldParse(),
  144. ':nth-child( 2n + 3 )': shouldParseTo(':nth-child(2n + 3)')
  145. }).run();
  146. vows.describe('Negation Selectors').addBatch({
  147. ':not(foo|bar)': shouldParse(),
  148. ':not(*|bar)': shouldParse(),
  149. ':not(foo|*)': shouldParse(),
  150. ':not(*|*)': shouldParse(),
  151. ':not(#blah)': shouldParse(),
  152. ':not(.blah)': shouldParse(),
  153. ':not([foo])': shouldParse(),
  154. ':not([foo^="bar"])': shouldParse(),
  155. ':not([baz|foo~="bar"])': shouldParse(),
  156. ':not(:hover)': shouldParse(),
  157. ':not(:nth-child(2n + 3))': shouldParse(),
  158. // Not technically allowed, but what the heck
  159. ':not(:not(#foo))': shouldParse(),
  160. ':not(a#foo.bar)': shouldParse(),
  161. ':not(#foo .bar > baz)': shouldParse(),
  162. ':not(h1, h2, h3)': shouldParse()
  163. }).run();
  164. vows.describe('moz-any Selector').addBatch({
  165. ':-moz-any(h1, h2, h3)': shouldParse(),
  166. ':-moz-any(.foo)': shouldParse(),
  167. ':-moz-any(foo bar, .baz > .bang)': shouldParse()
  168. }).run();
  169. vows.describe('Namespaced Selectors').addBatch({
  170. 'foo|E': shouldParse(),
  171. '*|E': shouldParse(),
  172. 'foo|*': shouldParse(),
  173. '*|*': shouldParse()
  174. }).run();
  175. vows.describe('Namespaced Attribute Selectors').addBatch({
  176. '[foo|bar=baz]': shouldParse(),
  177. '[*|bar=baz]': shouldParse(),
  178. '[foo|bar|=baz]': shouldParse()
  179. }).run();
  180. vows.describe('Comma Selectors').addBatch({
  181. 'E, F': shouldParse(),
  182. 'E F, G H': shouldParse(),
  183. 'E > F, G > H': shouldParse()
  184. }).run();
  185. vows.describe('Selectors with Newlines').addBatch({
  186. "E,\nF": shouldParse(),
  187. "E\nF": shouldParse(),
  188. "E, F\nG, H": shouldParse()
  189. }).run();
  190. vows.describe('Expression Fallback Selectors').addBatch({
  191. '0%': shouldParse(),
  192. '60%': shouldParse(),
  193. '100%': shouldParse(),
  194. '12px': shouldParse(),
  195. '"foo"': shouldParse()
  196. }).run();
  197. vows.describe('Functional Pseudo Selectors').addBatch({
  198. ':foo("bar")': shouldParse(),
  199. ':foo(bar)': shouldParse(),
  200. ':foo(12px)': shouldParse(),
  201. ':foo(+)': shouldParse(),
  202. ':foo(-)': shouldParse(),
  203. ':foo(+"bar")': shouldParse(),
  204. ':foo(-++--baz-"bar"12px)': shouldParse()
  205. }).run();
  206. vows.describe('Selector Hacks').addBatch({
  207. '> E': shouldParse(),
  208. '+ E': shouldParse(),
  209. '~ E': shouldParse(),
  210. '> > E': shouldParse(),
  211. '>> E': shouldParseTo('> > E'),
  212. 'E*': shouldParse(),
  213. 'E*.foo': shouldParse(),
  214. 'E*:hover': shouldParse()
  215. }).run();