@@ -42,6 +42,8 @@ add_task(async function () {
4242 await pushPref ( "layout.css.properties-and-values.enabled" , true ) ;
4343 // Enable anchor positioning
4444 await pushPref ( "layout.css.anchor-positioning.enabled" , true ) ;
45+ // Enable @custom -media
46+ await pushPref ( "layout.css.custom-media.enabled" , true ) ;
4547
4648 const { ui } = await openStyleEditorForURL ( TESTCASE_URI ) ;
4749
@@ -91,7 +93,7 @@ async function testInlineAtRulesEditor(ui, editor) {
9193 is ( sidebar . hidden , false , "sidebar is showing on editor with @media" ) ;
9294
9395 const entries = sidebar . querySelectorAll ( ".at-rule-label" ) ;
94- is ( entries . length , 8 , "8 at-rules displayed in sidebar" ) ;
96+ is ( entries . length , 14 , "14 at-rules displayed in sidebar" ) ;
9597
9698 await testRule ( {
9799 ui,
@@ -166,6 +168,70 @@ async function testInlineAtRulesEditor(ui, editor) {
166168 type : "position-try" ,
167169 positionTryName : "--pt-custom-bottom" ,
168170 } ) ;
171+
172+ await testRule ( {
173+ ui,
174+ editor,
175+ rule : entries [ 8 ] ,
176+ line : 42 ,
177+ type : "custom-media" ,
178+ customMediaName : "--mobile-breakpoint" ,
179+ customMediaQuery : [
180+ { text : "(width < 320px) and (height < 1420px)" } ,
181+ { text : ", " } ,
182+ { text : "not print" } ,
183+ ] ,
184+ } ) ;
185+
186+ await testRule ( {
187+ ui,
188+ editor,
189+ rule : entries [ 9 ] ,
190+ line : 43 ,
191+ type : "custom-media" ,
192+ customMediaName : "--enabled" ,
193+ customMediaQuery : [ { text : "true" } ] ,
194+ } ) ;
195+
196+ await testRule ( {
197+ ui,
198+ editor,
199+ rule : entries [ 10 ] ,
200+ line : 44 ,
201+ type : "custom-media" ,
202+ customMediaName : "--disabled" ,
203+ customMediaQuery : [ { text : "false" , matches : false } ] ,
204+ } ) ;
205+
206+ await testRule ( {
207+ ui,
208+ editor,
209+ rule : entries [ 11 ] ,
210+ line : 49 ,
211+ type : "media" ,
212+ conditionText : "(--mobile-breakpoint)" ,
213+ matches : false ,
214+ } ) ;
215+
216+ await testRule ( {
217+ ui,
218+ editor,
219+ rule : entries [ 12 ] ,
220+ line : 53 ,
221+ type : "media" ,
222+ conditionText : "(--enabled)" ,
223+ matches : false ,
224+ } ) ;
225+
226+ await testRule ( {
227+ ui,
228+ editor,
229+ rule : entries [ 13 ] ,
230+ line : 57 ,
231+ type : "media" ,
232+ conditionText : "(--disabled)" ,
233+ matches : false ,
234+ } ) ;
169235}
170236
171237async function testMediaEditor ( ui , editor ) {
@@ -298,6 +364,12 @@ async function testMediaRuleAdded(ui, editor) {
298364 * @param {string } options.layerName: Optional name of the @layer
299365 * @param {string } options.positionTryName: Name of the @position-try if type is "position-try"
300366 * @param {string } options.propertyName: Name of the @property if type is "property"
367+ * @param {string } options.customMediaName: Name of the @custom-media if type is "custom-media"
368+ * @param {Array<object> } options.customMediaQuery: query parts of the @custom-media if type is "custom-media"
369+ * @param {string } options.customMediaQuery[].text: the query string of the part of the @custom-media
370+ * if type is "custom-media"
371+ * @param {boolean } options.customMediaQuery[].matches: whether or not this part is style as matching,
372+ * if type is "custom-media". Defaults to true.
301373 * @param {number } options.line: Line of the rule
302374 * @param {string } options.type: The type of the rule (container, layer, media, support, property ).
303375 * Defaults to "media".
@@ -311,6 +383,8 @@ async function testRule({
311383 layerName,
312384 positionTryName,
313385 propertyName,
386+ customMediaName,
387+ customMediaQuery,
314388 line,
315389 type = "media" ,
316390} ) {
@@ -323,11 +397,52 @@ async function testRule({
323397 } else if ( type === "position-try" ) {
324398 name = positionTryName ;
325399 }
326- is (
327- atTypeEl . textContent ,
328- `@${ type } \u00A0${ name ? `${ name } \u00A0` : "" } ` ,
329- "label for at-rule type is correct"
330- ) ;
400+
401+ if ( type === "custom-media" ) {
402+ const atTypeChilNodes = Array . from ( atTypeEl . childNodes ) ;
403+ is (
404+ atTypeChilNodes . shift ( ) . textContent ,
405+ `@custom-media\u00A0` ,
406+ "label for @custom-media is correct"
407+ ) ;
408+ is (
409+ atTypeChilNodes . shift ( ) . textContent ,
410+ `${ customMediaName } ` ,
411+ "name for @custom-media is correct"
412+ ) ;
413+ is (
414+ atTypeChilNodes . length ,
415+ customMediaQuery . length ,
416+ `Got expected number of children of @custom-media (got ${ JSON . stringify ( atTypeChilNodes . map ( n => n . textContent ) ) } )`
417+ ) ;
418+ for ( let i = 0 ; i < atTypeChilNodes . length ; i ++ ) {
419+ const node = atTypeChilNodes [ i ] ;
420+ is (
421+ node . textContent ,
422+ customMediaQuery [ i ] . text ,
423+ `Got expected text for part #${ i } of @custom-media`
424+ ) ;
425+ if ( customMediaQuery [ i ] . matches ?? true ) {
426+ ok (
427+ // handle TextNode
428+ ! node . classList ||
429+ ! node . classList . contains ( "media-condition-unmatched" ) ,
430+ `Text for part #${ i } of @custom-media ("${ node . textContent } ") does not have unmatching class`
431+ ) ;
432+ } else {
433+ ok (
434+ node . classList . contains ( "media-condition-unmatched" ) ,
435+ `Text for part #${ i } of @custom-media ("${ node . textContent } ") has expected unmatching class`
436+ ) ;
437+ }
438+ }
439+ } else {
440+ is (
441+ atTypeEl . textContent ,
442+ `@${ type } \u00A0${ name ? `${ name } \u00A0` : "" } ` ,
443+ "label for at-rule type is correct"
444+ ) ;
445+ }
331446
332447 const cond = rule . querySelector ( ".at-rule-condition" ) ;
333448 is (
0 commit comments